当前位置:   article > 正文

C++的二分算法

C++的二分算法

 二分算法模板:

  1. int L=-1,R=n;
  2. while(L+1!=R)
  3. {
  4. int mid=L+R>>1;
  5. if( ) L=mid;
  6. else R=mid;
  7. //最后根据你所分左右两边区间的结果
  8. //选取L或者R作为结果
  9. }

 

模板细讲:

为什么L的初始值为-1,R的初始值为N

首先,如果二分本来就没有结果,比如对于本文例题 1 2 2 3 3 4,,如果你要寻找第一个 >=5 的数,你会发现,整个过程都在执行L=mid,最后得到的结果中,R是等于下标6的,他明显这个时候是越界的,说明我们找不到要寻找的数字,而如果我们一开始将R赋值为n-1,也就是赋值为下标5的时候,他返回的R是5,是没有越界的,被我们当成了答案,但其实这时候我们的二分是没有答案的,就发生了错误;其次,L最小值为-1,R最小值只能取到1,因为L+1!=R为循环结束条件,R最大值为N,同理则L的最大值为N-2,则(L+R)/2的取值范围是 [0,N)mid的值始终位于0到N的左闭右开区间里面,不会发生越界的错误;

为什么循环结束的条件是while(L+1!=R)?

   之前学过二分的小伙伴可能会发现,之前学的二分,他循环结束的条件是while(L<R)

   而这边给出的循环条件是while(L+1!=R) 其实,就是当L和R相邻的时候,循环就结束,而原本的while(L<R)

是当两区间重合以后,循环才结束,所以之前我们需要判断对mid进行加一或者减一的操作,而且因为区间重合的问题,最后返回的L、R还要再进行判断,而这边的这个二分,因为区间反回的是不重合的两区间,只有L=mid和R=mid这两种情况,最后根据需要返回L或者R;

不会陷入死循环

   对于比较奇葩的情况,比如数组大小为1或者2

   比如int a[1],b[2];

   由于我们是while(L+1!=R)结束循环,也就是当L和R相邻的时候结束条件

   对于a[1],他的下标为0 此时L=-1,R=n也就是1

   对于b[2],他的下标为0,1 此时L=-1,R=n也就是2

   所以无论何种情况,初始的L+1始终小于R,历经循环后最终L和R相邻,不会出现一开始L就和R重合等情况导致出现while(L+1!=R)循环不能结束的情况

  1. #include<iostream>
  2. /*给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。
  3. 对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
  4. 如果数组中不存在该元素,则返回 -1。
  5. 输入格式
  6. 第一行包含整数 n 和 q,表示数组长度和询问个数。
  7. 第二行包含 n 个整数(均在 1∼100001∼10000 范围内),表示完整数组。
  8. 接下来 q 行,每行包含一个整数 k,表示一个询问元素。
  9. */
  10. /*
  11. 6 3
  12. 1 2 2 3 3 4
  13. 3
  14. 4
  15. 5
  16. */
  17. using namespace std;
  18. const int N=1e5+5;
  19. int n,m,q[N];
  20. int main(){
  21. scanf("%d %d",&n,&m);
  22. for(int i=0;i<n;i++) scanf("%d",&q[i]);
  23. while(m--){
  24. int k;scanf("%d",&k);
  25. //寻找第一个等于K的坐标 我这边让二分的边界定为 左边为<5 右边>=5 则所求为r
  26. int l=-1,r=n;
  27. while(l+1!=r){//当l与r没有相接的时候,求边界
  28. int mid=l+r>>1;//相当于(l+r)/2
  29. //下面找第一个>=5的坐标
  30. if(q[mid]>=k) r=mid;
  31. else l=mid;
  32. }
  33. //此时得到的r是第一个>=5的坐标
  34. if(q[r]!=k) printf("-1 -1\n");
  35. else{
  36. printf("%d ",r);
  37. //现在找最后一个<=5的数字 我这边让二分的左边为<=5 右边为>5 则所求为ll
  38. int ll=-1,rr=n;
  39. while(ll+1!=rr){
  40. int mid=ll+rr>>1;
  41. if(q[mid]<=k) ll=mid;
  42. else rr=mid;
  43. }
  44. if(q[ll]!=k) printf("%d\n",r);
  45. else printf("%d\n",ll);
  46. }
  47. }
  48. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/47813
推荐阅读
相关标签
  

闽ICP备14008679号