二分模板
参考:acwing_二分模板
描述:假设目标值在区间[l, r]
中,每次通过二分法将目标值范围缩小一半。
例子:升序不重复序列中找target值。
模板一:
二分法需要有一个判断条件,对于模板一,假如判断条件是nums[mid] < target
:
- 若判断条件成立,说明target值在mid右边(不包括mid),区间变为
[mid + 1, r]
; - 若判断条件不成立,说明target值在mid左边(包括mid),区间变为
[l, mid]
。
还有一个问题是中值mid的取法(向上取整还是向下取整),对于模板一,假设极端情况l = r - 1
,若我们采用向下取整,则mid = (l + r) //2 = l
:
- 若条件成立,则区间应该变为
[r, r]
,迭代结束。 - 若条件不成立,则区间变为
[l, l]
,迭代结束。
因此,模板一选用向下取整。
while l < r:
mid = (l + r) // 2
if conditions(mid):
l = mid + 1
else:
r = mid
模板二:
假设判断条件为nums[mid] > target
:
- 若条件成立,说明目标值在mid左边(不包括mid),则范围变为
[l, mid - 1]
; - 若条件不成立,说明目标值在mid右边(包括mid),则范围变为
[mid, r]
。
对于极端情况l = r -1
,若我们采用向下取整,mid = (l + r)//2 = l
:
- 若条件成立,范围变为
[l, l-1]
,范围错误; - 若条件不成立,范围变为
[l, r]
,无限循环。
若我们采用向上取整,mid = (l + r + 1)//2 = r
:
- 若条件成立,范围变为
[l, l]
,迭代结束; - 若条件不成立,范围变为
[r, r]
,迭代结束。
因此,模板二采用向上取整。
while l < r:
mid = (l + r + 1) // 2
if conditions(mid):
r = mid - 1
else:
l = mid
如果对你有帮助,就推荐+收藏吧!😜😜