前言
二分查找想必我们都老生常谈,但是每次在讨论边界时总搞错到底什么时候mid+1什么时候用<=,我本人也曾在此多次头疼过,所以我为大家整理出了四种常见的区间写法:闭区间写法、左闭右开区间写法、开区间写法和左开右闭区间写法。这四种写法主要在处理边界情况时略有差异,但主要核心思想是一致的。
一、闭区间写法
在闭区间写法中,将搜索范围被表示为一个闭区间 [left, right],即包含左右两端点。我们通过不断调整左右边界来逼近目标值,直至最终找到目标或确定目标不存在:
def binarySearch1(nums, target):
left, right = 0, len(nums) - 1 # 闭区间 [left, right]
while left <= right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 范围缩小到 [mid+1, right]
else:
right = mid - 1 # 范围缩小到 [left, mid-1]
return left
二、左闭右开区间写法
左闭右开区间写法使用半开半闭区间 [left, right),即左侧闭合而右侧开放。在这种写法中,循环条件和边界处理稍有不同:
def binarySearch2(nums, target):
left, right = 0, len(nums) # 左闭右开区间 [left, right)
while left < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 范围缩小到 [mid+1, right)
else:
right = mid # 范围缩小到 [left, mid)
return left
三、开区间写法
开区间写法使用开区间 (left, right),即左右两端点都不包含在内。这种写法在处理边界时需要特别注意,循环条件和边界更新也略有不同:
def binarySearch3(nums, target):
left, right = -1, len(nums) # 开区间 (left, right)
while left + 1 < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid # 范围缩小到 (mid, right)
else:
right = mid # 范围缩小到 (left, mid)
return right
四、左开右闭区间写法
左开右闭区间 (left, right],注意这里是mid = (left + right + 1) // 2 ,取中位数。
def binarySearch4(nums, target):
left, right = 0, len(nums) - 1 # 左开右闭区间 (left, right]
while left < right:
mid = (left + right + 1) // 2 # 注意这里取右中位数
if nums[mid] < target:
left = mid # 范围缩小到 (mid, right]
else:
right = mid - 1 # 范围缩小到 (left, mid-1]
return right + 1
五、总结
下面是总体代码的使用:
from typing import List
# 闭区间写法
def binarySearch1(nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1 # 闭区间 [left, right]
while left <= right:
# 依此循环改变俩端left, right位置直至接近target:
# nums[left-1] < target
# nums[right+1] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 此时查找范围缩小到 [mid+1, right]
else:
right = mid - 1 # 此时查找范围缩小到 [left, mid-1]
return left
# 左闭右开区间写法
def binarySearch2(nums: List[int], target: int) -> int:
left = 0
right = len(nums) # 左闭右开区间 [left, right)
while left < right:
# nums[left-1] < target
# nums[right] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 此时查找范围缩小到 [mid+1, right)
else:
right = mid # 此时查找范围缩小到 [left, mid)
return left # 这里返回 left 还是 right 都可以,因为循环结束后 left == right
# 开区间写法
def binarySearch3(nums: List[int], target: int) -> int:
left, right = -1, len(nums) # 开区间 (left, right)
while left + 1 < right:
# nums[left] < target
# nums[right] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid # 此时查找范围缩小到 (mid, right)
else:
right = mid # 此时查找范围缩小到 (left, mid)
return right
# 左开右闭区间写法
def binarySearch4(nums, target):
left, right = 0, len(nums) - 1 # 左开右闭区间 (left, right]
while left < right:
mid = (left + right + 1) // 2 # 注意这里取右中位数
if nums[mid] < target:
left = mid # 范围缩小到 (mid, right]
else:
right = mid - 1 # 范围缩小到 (left, mid-1]
return right + 1
nums = [-99, 5, 7, 7, 8, 8, 9, 10, 11, 99]
target = 9
index = binarySearch1(nums, target) # 选择其中一种写法即可
if index == len(nums) or nums[index] != target:
print("不存在该target或数组为空")
else:
print("该target下标位置未:", index) # 输出下标: 6
最最后,假如您也和我一样,在准备春招。欢迎加我微信shunwuyu,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!