二分法,三分法
二分法
二分法用来在有序数列中查找某个值是否存在
但其实,二分最广泛的应用不是查找某个值,而是二分答案+check
1.先将区间(左闭右开,不然可能会死循环)二分,每个区间的长度为1/2(right-left)
2.如果mid能满足题目要求,那么使left变为mid+1,否则使right变为mid
因为如果mid满足条件,那么[l,mid]区间肯定都满足条件,增大要求,否则减小要求
bool check(int x){} // 检查是否可行 while(l<r) { int mid=(l+r)/2; if(check(mid)) l=mid+1; else r=mid; }
最终答案为l-1
分析一下最终答案是什么,由于只要能进if,则l等于满足条件的数+1,则最后二分出来的数值为最大的满足条件的数+1,即ans要-1
最终二分出来的数值为
若if那一行写的是l=mid+1,则数值为第一个能进不了if(条件)的数(即不满足条件),
否则 若写的是r=mid,即为第一个能进得了if(条件)的数(即满足条件)
三分法
在区间内用两个mid将区间分成三份,这样的查找算法称为三分查找,也就是三分法,三分法常用于求解单峰函数的最值。
三分法和二分法有些类似,二分处理的是递增/减的函数,而三分处理的是先递增后递减(或相反)的函数(单峰函数)的最值
1.先将区间三分,每个区间的长度为1/3(right-left)
2.比较mid1和mid2的函数值谁大,如果mid1更大,right改为mid2,否则left改为mid1
3.若区间长度小于5,特判避免死循环
算法的正确性:
1、lmid与rmid在最值的同一侧。由于单峰函数在最大值(最小值)任意一侧都具有单调性,因此,lmid与rmid中,更大(小)的那个数自然更为靠近最值。此时,我们远离最值的那个区间不可能包含最值,因此可以舍弃。
2、lmid与rmid在最值的两侧。由于最值在中间的一个区间,因此我们舍弃一个区间后,并不会影响到最值
int ans=-1; int f(int x){}//求函数值 while(1) { if(r-l<5) { for(int i=l;i<=r;i++)ans=max(ans,f(i)); break; } int lm=l+(r-l)/3,rm=r-(r-l)/3; if(f(lm)<f(rm))l=lm; else r=rm; }
最终答案为ans