LeetCode 34在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组nums
,和一个目标值target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为O(log n)
的算法解决此问题。
实例 1:
输入: nums =
[5,7,7,8,8,10]
, target = 8输出:
[3, 4]
实例 2:
输入: nums =
[5,7,7,8,8,10]
, target = 6输出:
[-1, -1]
实例 3:
输入: nums =
[]
, target = 0输出:
[-1, -1]
题解
二分查找
由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。
考虑target
开始和结束位置,其实我们要找的就是数组中「第一个等于 target
的位置」(记为 leftIdx
)和「第一个大于target
的位置减一」(记为rightIdx
)。
二分查找中,寻找leftIdx
即为在数组中寻找第一个大于等于target
于的下标,寻找rightIdx
即为在数组中寻找第一个大于target
的下标,然后将下标减一。两者的判断条件不同,为了代码的复用,我们定义binarySearch(nums, target, lower)
表示在nums
数组中二分查找target
的位置,如果lower
为true
,则查找第一个大于等于target
的下标,否则查找第一个大于target
的下标。
最后,因为target
可能不存在数组中,因此我们需要重新校验我们得到的两个下标leftIdx
和rightIdx
,看是否符合条件,如果符合条件就返回[leftIdx,rightIdx]
,不符合就返回[−1,−1]
。
python">from typing import Listclass Solution:# lower标志来决定找的是左侧边界还是右侧边界def binary_search(self, nums: List[int], target: int, lower: bool) -> int:left, right = 0, len(nums) - 1ans = len(nums)while left <= right:mid = (left + right) // 2if nums[mid] > target or (lower and nums[mid] >= target):right = mid - 1ans = midelse:left = mid + 1return ansdef search_range(self, nums: List[int], target: int) -> List[int]:left_idx = self.binary_search(nums, target, True)right_idx = self.binary_search(nums, target, False) - 1if left_idx <= right_idx and right_idx < len(nums) and nums[left_idx] == target and nums[right_idx] == target:return [left_idx, right_idx]else:return [-1, -1]# 示例调用
solution = Solution()
nums = [5, 7, 7, 8, 8, 10]
target = 8
result = solution.search_range(nums, target)
print(result)
输出:
python">[3, 4]