二分的细节

  满足单调性的情况下,可以用二分法找出答案,复杂度为logn

  1.在整数范围内,闭区间[l,r]的二分,以l==r为结束条件。边界条件需要考虑几个问题,当l或r更新的时候范围是否有缩小(若无则选入死循环),是赋得新值之后l是否==r而不是>r;

  2.根据题目设计选取mid归属于左半区间还是右半区间,假设我们要在单调递增的数组里面找第一个 >=val的值  假设a[mid]符合条件,那么可知mid的右边全都符合条件,但不知道mid的左边有没有符合条件的数字,因此在划分区间的时候不可以将mid去掉,因此r=mid,l=mid+1;为了使r=l+1的时候l<=r,此时mid=(l+r)>>1==l;

1 int binary_1(int l,int r,int val)
2 {
3     while(l<r)
4     {
5         int mid=(l+r)>>1;
6         if(a[mid]>=val)    r=mid;else l=mid+1;
7     }
8     return l;
9 }

  3.假设还是一个单调递增的数列,取第一个<=val的值,假如a[mid]符合条件,则mid的左半部分都符合条件,右半部分不一定有符合条件的,因此不能舍去,l=mid,r=mid-1;mid=(l+r+1)>>1;当r=l+1时,mid=r,为了缩小边界,r=mid-1;

int binary_2(int l,int r,int val)
{
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(a[mid]<=val)    r=mid-1;else l=mid;
    }
    return l;
}

    其中用位运算>>1而不是用/2 是因为在遇到负数的时候>>1是向下取整, /2是向0取整

  4.可以把[1,n]扩大为[0,n] [1,n+1],当去到r取0,或者l取n+1的时候即无解

 

  5.在实数域上的二分只需要考虑精度,则确定精确度即可,抑或是二分固定次数

  

 1 double binary(double l,double r,double exp)
 2 {
 3     while(r-l>exp)
 4     {
 5         double mid=(l+r)/2;
 6         if(cal(mid)) l=mid;else r=mid;
 7     }
 8     
 9     for(int i=1;i<=100;i++)
10     {
11         double mid=(l+r)/2;
12         if(cal(mid))l=mid;else r=mid;
13     }
14 }

  6.当l+r很大的时候有可能溢出,更妥当的写法是 l+(r-l)>>1     /    l+(r-l)>>1+1;

  7.三分法求极值(单峰函数严格单调) 将区间三分,比较mid1和 mid2 极值点一定不在某个区间上,此区间为[l,mid1]或[mid2,r] 

  

double maxx(double l,double r,double exp)
{
    while(r-l>exp)
    {
        double k=r-l/3,mid1=l+k,mid2=r-k;
        if(f(mid1)<f(mid2))    l=mid1;else r=mid2;
    }
    return l;
}

  

猜你喜欢

转载自www.cnblogs.com/smoncaff/p/12178531.html