OI算法之二分

今天我们来总结一下二分。

概念

二分(Binary search),也称为折半法,是一种在有序数组中查找特定元素的搜索算法。

原理

二分的前提条件是数列一定要单调。

声明一下,计算 mid 时需要技巧防止溢出,建议写成: mid = left + (right - left) / 2。

以在一个升序数组中查找一个数为例。

它每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找。

二分一般用在最大值中求最小值或在最小值中求最大值里。

二分可以有效的降低时间复杂度因为每次查询都会去掉一半非答案,最后找到答案,如果数据范围是100且数列单调,二分就只需要7次查询就可以得到目标值。

比如我们常玩的猜数字。

主持人从1~100里选一个数,每次你可以问TA是不是这个数,TA会回答是或不是同时不是会告诉你大了或小了。

第一次,我们选择了50,大了。

第二次,我们选择了25,小了。

第三次,我们选择了37,小了。

第四次,我们选择了42,小了。

第五次,我们选择了46,小了。

第六次,我们选择了48,小了。

第七次,我们选择了49,正确。

我们按普通枚举方法需要100次

我们看出来这是一个稳定且时间复杂度低的算法,在这个例子中时间复杂度最坏为 \(O(\log n)\),最好为 \(O(1)\)

code:

int binary_search(int start, int end, int key) {
  int ret = -1;  //未找到目标值
  int mid;
  while (start <= end) {
    mid = start + ((end - start) >> 1);  // 上文提到的溢出
    if (arr[mid] < key)
      start = mid + 1;
    else if (arr[mid] > key)
      end=mid-1;
    else {  // 不大于也不小于就是相等
      ret = mid;
      break;
    }
  }
  return ret;
}

二分答案

我们看下这道

我们发现符合单调且二分可行。

这次和猜数字不同在于,我们二分的内容是ans,然后每次查询判断答案是否合法,不合法看是大了小了,然后按照猜数字的思路即可。

经典练习题

P1

P2

P3

P4

P5

posted @ 2025-06-03 13:02  Fools_Sparkle  阅读(52)  评论(0)    收藏  举报