二分法比较重要,然后又一定的模板。在此基础上可以进行一系列的修改,然后达到题目要求。需要注意有几个地方,二分法容易出错。
整数二分
二分法分整数二分
和浮点数二分
。
二分法使用的范围: 是以一个点,满足一个性质,可以把一个区间分成两个部分。这个性质可以是单调性
也可以是其他的性质。
两个模板可以求两个点:
第一个求黑色点的:
1 |
|
第二个球蓝色的点:
1 | // l, r 分别表示left左边界,和r有边界。 |
二分的取整比较重要,有时候需要进行向上取证。不然就会一直进行循环。 当 l = mid
的时候需要进行向上取证,而 r = mid
不需要进行向上取整数。
- l = mid的时候, 当l = r - 1, 如果是mid = l + r >> 1,如果cheak(mid) == true, 那么l = mid, 区间任然是
[l, r]
- 所以l = mid 的时候, mid = l + r + 1 >> 1; 进行向上取整数。
- r不用此考虑,因为r本身就是向下取整,而且 while ( l < r) 当r向下取整后就会终止循环。
- 所以在归并排序中mid = l + r >> 1, 左边分成
[l, mid]
右边是[mid + 1, r]
区间。
浮点数二分
浮点数二分不用考虑边界情况,左边界和右边界都是一样的。以一个点向左划分和向右划分都是一样的。所以不存在划分的边界条件。
以开三次方为例子。数据范围 -1000000 <= n <= 1000000
1 | double n; |
1 | double n; |
还有一种写法,就是循环100次数:
1 | double n; |
PS:
这里r - l > 1e-8 是提升精度的方式, 要求保留6位小数点的话,那么精度就要求1e8。循环100次也是提升精度的方式。 这里mid * mid * mid >= x
, 等于符号无所谓,可有可无,因为取不到等于的情况。