给定一个按照升序排列的整数数组 nums,和一个目标值 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]
依据于之前所做的题目,如果忽略对于时间复杂度的控制,采用暴力的方法是可以吗解这道题的。首先通过list.index(target)
找到第一个等于target
的元素的索引,然后判断它后面的元素是不是等于target
,直到遇到第一个不等于target
的元素,然后将其前一个索引作为终止位置,最后返回索引区间即可。但是这样的方法时间复杂度为 O ( n ) O(n) O(n),不满足要求。
为了达到 O ( log n ) O(\log n) O(logn)的时间复杂度要求,一种转换的基本思路就是使用二分查找。另外需要注意的地方在于,数组中的target
此时可能有多个重复的值,但给定的数组本身就是升序排列的,所以相同的taget
必定是挨在一起的。所以在二分查找的过程中需要如下的判断:
- 如果
nums[mid] == target
,则需要向前和向后继续走,直到分别遇到第一个不等于target
的元素,此时两个方向的终止位置就是所求区间的左右索引,走的时候同样注意边界 - 如果
nums[mid] < target
,说明target
位于右端,则更新指针r
- 如果
nums[mid] > target
,说明target
位于左端,则更新指针l
AC code
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
if nums == []: return [-1, -1]
if len(nums) == 1 and nums[0] == target:
return [0,0]
elif len(nums) == 1 and nums[0] != target:
return [-1, -1]
# 题目要求复杂度为O(logn),所以不能使用线性查找
# 二分查找可用
l = 0
r = len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
t = mid
while mid + 1 <= r and nums[mid + 1] == target:
mid = mid + 1
e = mid
while t - 1 >= 0 and nums[t - 1] == target :
t = t - 1
s = t
return [s,e]
elif nums[mid] < target:
l = mid + 1
else:
r = mid - 1
return [-1, -1]