二分法,三分法

二分法

二分法用来在有序数列中查找某个值是否存在

但其实,二分最广泛的应用不是查找某个值,而是二分答案+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

原文地址:https://www.cnblogs.com/lher/p/7481554.html