# 二分查找及常见变体

·  阅读 231

## 代码分析

• 区间的左右开闭问题: `[0, length - 1]`
• 循环边界: `while left < right`，这样可以保证最终返回值`left == right`，随便返回哪个都可以
• 区间`[left.. right]`可以划分为两种情况：
• 分为`[left..mid]``[mid+1..right]`，分别对应`right = mid``left = mid + 1`
• 分为`[left..mid-1]``[mid..right]`，分别对应`right = mid-1``left = mid`。在这种情况下，需要将`mid = left + (right - left) / 2`修改为 `mid = left + (right - left + 1) / 2`，否则将出现死循环。

## 常见二分变体

### 查找第一个等于给定值的元素

``````def firstEquals(nums, target):
left, right = 0, len(nums) - 1
while left < right:
mid = left + (right - left)//2 # 防止溢出, //表示整除
if nums[mid] < target:
left = mid + 1
else:
right = mid # 收缩右边界
return left

### 查找最后一个等于给定值的元素

``````def lastEquals(nums, target):
left, right = 0, len(nums) - 1
mid = left + (right - left + 1) // 2
while left < right:
if nums[mid] > target:
right = mid - 1
else :
left = mid
return left

### 查找第一个大于等于给定值的元素

``````def firstLessEquals(nums, target):
left, right = 0, len(nums) - 1
mid = left + (right - left) // 2
while left < right:
if nums[mid] < target:
left = mid + 1
else :
right = mid
return left

### 查找最后一个小于等于给定值的元素

``````def firstLessEquals(nums, target):
left, right = 0, len(nums) - 1
mid = left + (right - left + 1) // 2
while left < right:
if nums[mid] > target:
right = mid - 1
else :
left = mid
return left