首先来看整数二分最经典的应用
Q. 从升序的数组
nums中找到值为x的点,并返回其下标,若不存在,返回-1。
为了解决这个问题,我们可以将区间从中间一分为二,判断中点是否是 x,若不是,再在子区间中查找,代码如下。
1 | int binsearch(vector<int> nums, int target) { |
将这个问题拓展一下。
Q. 从升序数组
nums中找到值大于等于x下标最小的点。
对于这个问题,也可以使用二分进行求解。基本思路依然为检查 nums[mid] 和 x 之间的关系:若 nums[mid] >= x 那么下标最小的点一定为 mid 本身或其左侧,否则下标最小的点一定处在 mid 右侧。代码如下。
1 | int binsearch(vector<int> nums, int target) { |
这里有两个小细节:1. right 初始时取到 nums.size(),因为存在 nums 数组中所有的数均小于 x 的情况,此时的大于等于 x 的最小的点应处于 nums.size()。2. 根据分析,我们将区间划分为 [left, mid] 或 [mid + 1, right] 两部分,我们在取中点时应取 (left + right) / 2,即下取整,可以使这两个区间不会存在 mid == right 或是 mid + 1 == left 的情况,避免死循环。
类似的,有另一个拓展的问题。
Q. 从升序数组
nums中找到值小于等于x下标最大的点。
这里可以类比上面的分析,得到下面的代码。
1 | int binsearch(vector<int> nums, int target) { |
这里同样需要注意几个小细节:1. nums 数组初始从 1 开始存储数字,left 初始置为 0,应对数组中所有数均大于 x 的情况。2.根据区间划分,此时中点应该取 mid = (left + right + 1) / 2 以避免死循环。
类似的,我们可以很简单的类推得到下面几个问题的代码。
Q. 从升序数组
nums中找到值大于x下标最小的点。Q. 从升序数组
nums中找到值小于x下标最大的点。Q. 从降序数组
nums中找到值小于(等于)x下标最小的点。Q. 从降序数组
nums中找到值大于(等于)x下标最大的点。
浮点二分并不存在区间端点问题,只需要控制精度。
下面是浮点二分最经典的一个应用场景。
Q. 求
sqrt(x)(x >= 1),保留小数点后四位。
对于这个问题,我们可以利用二分快速对解的区间进行逼近,从而得到近似解,代码如下。
1 | double binsqrt(double x) { |
上面代码中的 eps 用于控制精度,一般设置为题目要求精度再低两个数量级。