学习笔记:三分

本文介绍了一种高效的查找算法——三分法。三分法适用于有峰值的数据序列,并通过不断缩小搜索范围来逼近最大值或最小值。文章详细解释了整数和浮点数场景下的实现方法,包括如何缩小区间和具体的代码示例。

简述

类比二分,三分是把原来的序列分成3份,通过大小关系的比较来收缩空间,进行逼值,适用于对有峰值的数据(也就是小山一样)来找最值,准确的描述一下就是先单增后单减,或者先单减后单增,当然完全单调的数据也是可以的。

具体实现

如何缩小区间?

以上凸为例,当前有l,ml,mr,r四个点(按照从小到大排序)

f(ml)>f(mr)时,说明峰在mr左边,那么让r=mr,否则让l=ml;

下凸方向相反

怎么分?

浮点数

这个很好处理,不停夹逼直到区间小于eps

整数

这里稍微有点不一样,因为整数运算的性质并不是那么好,也没有二分那样特殊,边界处理会出问题, 大概两种方法来处理。

第一种:先二分,再二分,就是1/4,1/2这两个位置,很方便,没有边界,但是时间复杂度最坏情况下差了一点。

第二种:找三等分点,在r-l<=2的时候,直接暴力枚举最后的1~3个点,我比较喜欢这个。

时间复杂度

网上有很多奇奇怪怪的分析,我有点不以为然。

按照第二种处理方式分析每次我们可以把区间缩小为原来的2/3

设我们进行了t次收缩,则:
n(2/3)t=1n∗(2/3)t=1

t=logn1.5t=log1.5n

然后每次进行了两次运算,所以一共是O(2logn1.52log1.5n)

网上有些认为是O(2log3n)或者O(3log3n),并不知道怎么来的,但是我的和这两种算下来数值上差不多,所以也不必太纠结,大概就是log级别的时间复杂度,而且比二分高。

代码

这是一段整数上凸的代码,其它的类比一下吧。

LL sanfen(int L,int R)
{
    while(R-L>2)
    {
        int midl=L+(R-L)/3,midr=R-(R-L)/3;
        if(f(midl)>f(midr))R=midr;
        else L=midl;
    }
    LL ret=-inf;
    for(int i=L;i<=R;i++)
        ret=max(ret,f(i));
    return ret;
}

注意

  • 上凸和下凸代码不同,不要混用
  • 注意分的时候要用差值/3,不能像二分一样全部加起来/3。
  • 整数注意分界,>=3(>2),而且简单数据可能看不出来,所以注意一点。
  • 奇怪的是很多时候即使你三分写得很错,答案还是很对,所以一个是注意怀疑三分算法正确性,一个是可以考虑乱搞。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值