理解二分法的不同实现
参考资料
二分法介绍
二分查找法主要是解决在“一堆数中找出指定的数”这类问题,这“一堆数”必须有以下特征:
- 存储在数组中
- 有序排列
思想
假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。
二分和单调性的关系
有单调性的一定可以二分,但可以二分的不一定有单调性,即没有单调性也可以二分。
实现
方式
递归
1 | int bsearch(int array[], int low, int high, int target) |
stack
1 | int bsearchWithoutRecursion(int array[], int low, int high, int target) |
整数二分实现
需要考虑边界问题,否则会陷入死循环。
版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。
1 | int bsearch_1(int l, int r) |
版本2
当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。
1 | int bsearch_2(int l, int r) |
浮点数二分实现
无需考虑边界问题。
找到一个区间[l, r], 使得答案一定在区间中。
找到一个判断条件,使得判断条件具有二段性,并且答案一定是该二段性的分界点。
分析中点mid = (l + r) / 2 在该判断条件下是否成立。
如果成立,考虑答案在哪个区间;
如果不成立,考虑答案在哪个区间。确定更新方式r = mid 或 l = mid。
1 | bool check(double x) {/* ... */} // 检查x是否满足某种性质 |
关于浮点数二分中区间精度的选取:
一般来说区间精度为1e-6就很高了。如果要求结果保留4位小数,那么精度可以取1e-6;如果要求结果保留5位小数,那么区间精度可以取1e-7。以此类推……
简言之,区间精度至少要比要保留的小数位数高2位。