题目描述:给定一个包含 n 个整数的排序数组,找出给定目标值 target 的起始和结束位置。如果目标值不在数组中,则返回[-1, -1]
样例:给出[5, 7, 7, 8, 8, 10]和目标值target=8,返回[3, 4]
还记得在学习二分查找时遇到的第一个问题吗?要求返回目标值第一次在数组中出现的位置,详见:点击打开链接。
那么现在问题就可以简化了:我们可以先通过二分法找到目标的任意一个位置,比如,在样例[5, 7, 7, 8, 8, 10]中8所在位置是3和4,我们找到任意一个位置(3或4)之后,在这一位将数组分割,例如,我们选择位于第3位的'8',将数组分割成[5, 7, 7, 8]和[8, 8, 10]两个部分,需要注意的是,两个数组都包含了我们选择的那个位,这样做的目的是防止其中一个数组完全不存在target.之后,再在向左边数组搜索target的第一个出现的位置,也就是target出现的区间的最左端的位置;在右边数组搜索target的最后一个出现的位置,也就是target出现的区间的最右端的位置。这两次查找都是二分法,其中,查找最左端位置的算法跟上面讲的那个问题一模一样,查找最右端位置的算法同理。
简单说,算法分为三步:
1. 二分法找到任意一个target
2. 以这个找到的target为分界线,将数组分成左右两部分
3. 分别查找左边数组最左端的target;右边数组最右端的target
代码照这个写就行:
class Solution:
"""
@param A : a list of integers
@param target : an integer to be searched
@return : a list of length 2, [index1, index2]
"""
def searchRange(self, A, target):
left, right = 0, len(A) - 1
result = []
while left <= right:
mid = (left + right) // 2
if A[mid] == target:
result.append(self.lower_bound(A, left, mid, target))
result.append(self.upper_bound(A, mid, right, target))
return result
elif A[mid] > target:
right = mid - 1
else:
left = mid + 1
return [-1, -1]
def lower_bound(self, array, left, right, target):
left, right = 0, len(array) - 1
while left <= right:
mid = (left + right) // 2
if array[mid] >= target:
right = mid - 1
else:
left = mid + 1
return left
def upper_bound(self, array, left, right, target):
left, right = 0, len(array) - 1
while left <= right:
mid = (left + right) // 2
if array[mid] <= target:
left = mid + 1
else:
right = mid - 1
return right
# write your code here
其中,lower_bound和upper_bound是分别向左右两边搜寻的函数,他们里面的形参left和right表示这两个数组的起止位置。由算法结构知:时间复杂度O(logn)