前言
二分查找是在一个有序数组中,每次查找将数组分成两半,并将查找值与中间值比较,是一个快速查找(O(logn))的方法。
例如,在 [1,2,3,4,5,5,7] 中查找 7:
- 获取中间值 4,4<5,所以在右半边 [5,5,7] 继续查找。
- 获取中间值 5,5<7,所以在右半边 [7] 继续查找。
- 数组中只有一个元素 7,查找完成。
二分答案与其非常相似,是在一个具有单调性的问题中,查找最值的方法。
基本思想
单调性
什么问题具有单调性呢?
以下是几个具有单调性的问题:
- 数字炸弹(伪):已知数字 x∈[1,n] 后全是炸弹,求出最后一个安全位置。
- NOIP2015 提高组 跳石头:已知隔一段距离有一块石头,求出拆除 x 个石头后,最近两块石头间距离的最大值。
以上问题都有共同点:
- 问题有确定的边界。
- 一定程度上,当 x 满足条件时,比 x 大或小的数不满足条件。
处理问题
根据以上性质,可以按以下思路求解:
- 首先,给出一段区间 [1,N]。
- 之后,求出中间值 mid,并验证答案为 mid 时是否满足条件。
- 根据单调性,缩小区间。
注意事项
在使用二分答案过程中,需要注意以下问题:
- 初始区间应该含最终结果。
- 注意不能出现死循环。
- 编写正确的验证答案算法。
补充
对上述“数字炸弹(伪)”的演示:
已知在 [1,100] 的整数中,78 以后是炸弹,求出最大的安全位置。
虽然显然安全位置等于 78−1,但是此处为了演示,使用二分答案。
- 定义二分搜索的上下界:下界是 1,上界是 100。
- 二分搜索:在每一步中,我们计算中间值 mid,并检查它是否是安全位置(即是否小于或等于 78)。
- 调整搜索范围:
- 如果 mid 是安全位置,并且我们希望找到尽可能大的安全位置,那么我们将下界更新为 mid+1 并继续搜索。
- 如果 mid 不是安全位置,那么我们将上界更新为 mid−1。
- 终止条件:当上下界相遇或错过时,搜索结束。
以下是演示:
- l=1,r=100,mid=50,此时 mid 为较小值,l→mid+1。
- l=51,r=100,mid=75,此时 mid 为较小值,l→mid+1。
- l=76,r=100,mid=88,此时 mid 为较大值,r→mid−1。
- l=76,r=87,mid=81,此时 mid 为较大值,r→mid−1。
- l=76,r=80,mid=78,此时 mid 为较大值,r→mid−1。
- l=76,r=77,mid=76,此时 mid 为较小值,l→mid+1。
- l=77,r=77,mid=77,此时 l=r,查找结束。所求值为 77。