二分

Posted on 2022-02-13 19:12  ZheyuHarry  阅读(327)  评论(0编辑  收藏  举报

        今天要介绍的是一种比较常见但是效率很高的算法,就是二分法。因为二分法有着O(logn)的优秀时间复杂度,所以我们常常会用到它。

     

     但是呢二分主要是运用于已经排好序了的序列,通常我们知道一个答案区间,然后二分的去寻找符合题意的answer;或者我们已知一个序列,我们要通过二分的方法去寻找它的位置,或者说是起始位置和终止位置。

 

      二分呢,一般可以分为整数二分和实数二分,我们将会先介绍整数二分。

      二分的思想很简单,通过不断的调整左右边界,使之逼近目标值。

 

      整数二分最需要注意的问题就是边界问题,我们常常会因为边界问题思考过于粗糙,导致我们的程序陷入死循环或者某些情况未考虑导致答案错误。

 

      接下来上板子:

      //lower_bound Binary Search

     int l=0,r=n-1;

     while(l<r){

      int mid=l+r>>1;

      if(arr[mid]>=x) r=mid;

      else l=mid+1;    

}

 

     //upper_bound Binary Search

     int l=0,r=n-1;

 

     while(l<r){                         //保证了最后得到的下标l==r

 

      int mid=l+r+1>>1;           //这里加一是为了避免l+1==r时陷入死循环

 

      if(arr[mid]<=x) l=mid;

 

      else r=mid-1;    

 

}

//有这么一道模板题:789. 数的范围 - AcWing题库

 

    然后我们再看到实数二分,实数二分我们比较要多考虑的就是答案所要求的几位小数(有效数字),以及循环条件满足时边界该如何移动。

例题:790. 数的三次方根 - AcWing题库

int main()
{
double n;
cin>>n;
double l=-10000,r=10000;
double mid;
while(r-l>=1e-7){                    //这是因为要保留六位小数,所以误差值取为1e-7
mid=(l+r)/2;                            //这里就不用考虑加1了
if(mid*mid*mid>=n) r=mid;
else l=mid;                             //边界也变为mid而不是mid+1,因为是实数除法,不会陷入死循环
}
printf("%.6lf",mid);
return 0;
}

 

总之二分的例题有很多,如下(我之后遇到一些好题也会放上去的):

1.1996. 打乱字母 - AcWing题库

2.Problem - 1626C - Codeforces

3.Problem - 1632C - Codeforces

4.Problem - 1628A - Codeforces

5.4297. 截断数组 - AcWing题库  //这道题是在一个数组中去枚举去二分

6.D-[NOIP2001]一元三次方程求解_河北经贸大学2021-2022寒假第三次专题赛 (nowcoder.com)//实数二分

7.1659. 社交距离 I - AcWing题库  //贪心加二分