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,然后每次查询判断答案是否合法,不合法看是大了小了,然后按照猜数字的思路即可。

浙公网安备 33010602011771号