简述
类比二分,三分是把原来的序列分成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),而且简单数据可能看不出来,所以注意一点。
- 奇怪的是很多时候即使你三分写得很错,答案还是很对,所以一个是注意怀疑三分算法正确性,一个是可以考虑乱搞。

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

被折叠的 条评论
为什么被折叠?



