📅  最后修改于: 2023-12-03 15:06:20.582000             🧑  作者: Mango
二进制搜索(binary search)是一种在有序数组中查找特定元素的常用算法。但是有时候需要对二进制搜索进行一些变形,以满足特定的需求。本文将介绍二进制搜索的三种变体:上下界二分、第一个出现和最后一个出现。
在二分查找的过程中,我们只需要判断当前元素是否等于目标元素,如果不等于,则需要将搜索区间缩小一半。但是在某些情况下,我们需要查找和目标元素相等的序列中的全部元素,这时就需要使用上下界二分。
有时候需要查找特定值在数组中的出现范围(比如查找第一个大于某个值的元素或最后一个小于某个值的元素),即查找包括特定值在内的某个数值范围。这时候,需要考虑到查找区间的上下界。具体思路如下:
这里,我们定义了两个辅助函数:分别用于查找上下界。代码如下:
def find_lower_bound(nums: List[int], target: int) -> int:
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = lo + (hi - lo) // 2
if nums[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return lo
def find_upper_bound(nums: List[int], target: int) -> int:
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = lo + (hi - lo) // 2
if nums[mid] <= target:
lo = mid + 1
else:
hi = mid - 1
return hi
然后,我们可以使用这两个函数来查找上下界。代码如下:
def search_range(nums: List[int], target: int) -> List[int]:
if not nums:
return [-1, -1]
low = find_lower_bound(nums, target)
high = find_upper_bound(nums, target)
if low <= high:
return [low, high]
else:
return [-1, -1]
这里的时间复杂度是 O(logn),空间复杂度是O(1)。
有时候需要查找某个元素在数组中的第一个出现位置或最后一个出现位置。这时候,可以考虑使用二分查找的一个变体——双指针二分查找。
具体思路:我们在正常的二分查找基础上,增加两个指针left和right,用于查找第一个出现的位置和最后一个出现的位置。具体来说:
代码实现如下:
def search_range(nums: List[int], target: int) -> List[int]:
if not nums:
return [-1, -1]
left, right = binary_search(nums, target)
if left == -1 or right == -1:
return [-1, -1]
while left > 0 and nums[left-1] == target:
left -= 1
while right < len(nums)-1 and nums[right+1] == target:
right += 1
return [left, right]
def binary_search(nums: List[int], target: int) -> Tuple[int, int]:
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid, mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1, -1
这里的时间复杂度同样是O(logn),空间复杂度是O(1)。