算法-二分答案
前言
二分查找是在一个有序数组中,每次查找将数组分成两半,并将查找值与中间值比较,是一个快速查找($O(\log n)$)的方法。
例如,在 $[1, 2, 3, 4, 5, 5, 7]$ 中查找 $7$:
- 获取中间值 $4$,$4 < 5$,所以在右半边 $[5, 5, 7]$ 继续查找。
- 获取中间值 $5$,$5 < 7$,所以在右半边 $[7]$ 继续查找。
- 数组中只有一个元素 $7$,查找完成。
二分答案与其非常相似,是在一个具有单调性的问题中,查找最值的方法。
基本思想
单调性
什么问题具有单调性呢?
以下是几个具有单调性的问题:
- 数字炸弹(伪):已知数字 $x \in [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 \rightarrow mid + 1$。
- $l=51,r=100,mid=75$,此时 $mid$ 为较小值,$l \rightarrow mid + 1$。
- $l=76,r=100,mid=88$,此时 $mid$ 为较大值,$r \rightarrow mid - 1$。
- $l=76,r=87,mid=81$,此时 $mid$ 为较大值,$r \rightarrow mid - 1$。
- $l=76,r=80,mid=78$,此时 $mid$ 为较大值,$r \rightarrow mid - 1$。
- $l=76,r=77,mid=76$,此时 $mid$ 为较小值,$l \rightarrow mid + 1$。
- $l=77,r=77,mid=77$,此时 $l=r$,查找结束。所求值为 $77$。