Given an array of integers nums
sorted in non-decreasing order, find the starting and ending position of a given target
value.
If target
is not found in the array, return [-1, -1]
.
You must write an algorithm with O(log n)
runtime complexity.
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8 Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6 Output: [-1,-1]
Example 3:
Input: nums = [], target = 0 Output: [-1,-1]
Constraints:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
is a non-decreasing array.-109 <= target <= 109
所有人看到这题都会想到肯定是二分查找法,但是这题难度在于中间值与目标值比较之后左边界或右边界该怎么移动。其实如果我们对lower bound和upper bound的概念很熟悉的话,那这题就变得很简单了。
对于一个有序数组,一个目标数的lower bound就是数组中第一个不小于该目标数的数,如果目标数存在的话那么lower bound就最左边的那个目标数;一个目标数的upper bound就是数组中第一个大于该目标数的数,如果目标数存在的话那么upper bound左边的那个数就是最右边的那个目标数。
因此本题就变成实现两个函数即lower_bound()和upper_bound(),这两函数就是用二分查找法的,代码也非常类似,只是判断边界移动的条件略有不同。(c++中有现成的函数)。
lower_bound()是要求最左边的那个数,因此碰到中间数与目标数相等时仍然是移动右边界。
upper_bound()是要求最右边的那个数,因此碰到中间数与目标数相等时仍然是移动左边界。
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
l = self.lower_bound(nums, target)
if l == len(nums) or nums[l] != target:
return [-1, -1]
r = self.upper_bound(nums, target)
return [l, r - 1]
def lower_bound(self, nums, target):
l, r = 0, len(nums) - 1
while l <= r:
mid = l + (r - l) // 2
if target <= nums[mid]:
r = mid - 1
else:
l = mid + 1
return l
def upper_bound(self, nums, target):
l, r = 0, len(nums) - 1
while l <= r:
mid = l + (r - l) // 2
if target < nums[mid]:
r = mid - 1
else:
l = mid + 1
return l