34. 在排序数组中查找元素的第一个和最后一个位置
个人
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
left = 0
right = len(nums)-1
if len(nums)==0:
return [-1,-1]
while left<=right:
middle = (left+right)//2
if nums[middle]==target:
M = middle
R = right
#left right 为相同target的上下界
#左边
right = M
while left<=right:
middle = (left+right)//2
if nums[middle]==target:
right = middle-1
else:
left = middle+1
lef_ans = left
#右边
left = M
right = R
while left<=right:
middle = (left+right)//2
if nums[middle]==target:
left = middle+1
else:
right = middle-1
rig_ans = right
return [lef_ans,rig_ans]
elif nums[middle]>target:
right = middle-1
elif nums[middle]<target:
left = middle+1
return [-1,-1]
灵神模板—下面的代码包含闭区间、左闭右开区间和开区间三种写法
# lower_bound 返回最小的满足 nums[i] >= target 的 i
# 如果数组为空,或者所有数都 < target,则返回 len(nums)
# 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
# 闭区间写法
def lower_bound(nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1 # 闭区间 [left, right]
while left <= right: # 区间不为空
# 循环不变量:
# 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 # 或者 right+1
# 左闭右开区间写法
def lower_bound2(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 # 或者 right
# 开区间写法
def lower_bound3(nums: List[int], target: int) -> int:
left, right = -1, len(nums) # 开区间 (left, right)
while left + 1 < right: # 区间不为空
mid = (left + right) // 2
# 循环不变量:
# nums[left] < target
# nums[right] >= target
if nums[mid] < target:
left = mid # 范围缩小到 (mid, right)
else:
right = mid # 范围缩小到 (left, mid)
return right # 或者 left+1
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
start = lower_bound(nums, target) # 选择其中一种写法即可
if start == len(nums) or nums[start] != target:
return [-1, -1]
# 如果 start 存在,那么 end 必定存在
end = lower_bound(nums, target + 1) - 1
return [start, end]
- 核心要素
- 注意区间开闭,三种都可以
- 循环结束条件:当前区间内没有元素
- 下一次二分查找区间:不能再查找(区间不包含)mid,防止死循环
- 返回值:大于等于target的第一个下标(注意循环不变量)
- 有序数组中二分查找的四种类型(下面的转换仅适用于数组中都是整数)
1. 第一个大于等于x的下标: low_bound(x)
2. 第一个大于x的下标:可以转换为`第一个大于等于 x+1 的下标` ,low_bound(x+1)
3. 最后一个一个小于x的下标:可以转换为`第一个大于等于 x 的下标` 的`左边位置`, low_bound(x) - 1;
4. 最后一个小于等于x的下标:可以转换为`第一个大于等于 x+1 的下标` 的 `左边位置`, low_bound(x+1) - 1