版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HappyRocking/article/details/83785478
给定一个升序整数数组,找到一个目标值的起始和结束位置。
如果目标值不存在,则返回 [-1,-1]。
示例:
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]
思路
在一个有序数组中查询某个目标值的位置,可以使用经典的二分法。
但是本题不仅需要查询位置,还需要查询最开始出现的位置和最晚出现的位置。
因此需要在二分法的基础上,进行修改,使得二分法可以返回一个数组,分别存放目标值的首尾位置。
我们使用递归法进行二分,每次递归进行:
1、寻找到当前数组的中位数
2、比较中位数与目标值的大小
- 若目标值=中位数,则说明最终结果的首尾位置会分别出现在左半部分和右半部分(包括中位数本身),因此需要分别递归计算出左半部分和右半部分的首尾位置,然后取出最小的首位置和最大的尾位置,作为最终结果。
- 若目标值<中位数,则说明最终结果的首尾位置只可能出现在左半部分,继续递归左半部分即可。
- 若目标值>中位数,则说明最终结果的首尾位置只可能出现在右半部分,继续递归右半部分即可。
3、递归结束条件
- 若当前数组小于等于2,则直接对所有元素扫描一遍,返回目标值的首尾位置。
小技巧:
1、若当前数组的首尾元素相等,则由于是有序数组,因此中间所有元素也都相等。这样不必继续递归,直接根据元素值是否等于目标值即可返回结果。
2、如果没有找到首尾位置,则建议首位置返回原数组的长度,尾位置返回-1。这是因为首位置的最大值是数组长度-1,尾位置最小值是0,但凡其他递归的结果中寻找到了目标值,那么两对结果进行比较时,只需要选择较小的首位置和较大的尾位置作为最终结果即可。
python实现
def searchRange(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
二分法。
在查找到target之后,继续使用二分法,查找起始和结束位置。
"""
def binary_search(nums, l, u, target, max_len):
'''
二分法查找nums的l~u之间等于target的元素,返回起始和结束位置。
如果不存在,则返回 (max_len, -1)
'''
# 递归结束条件1
if u - l <= 1: # 数组长度小于等于2
# 初始化首尾位置
start = max_len
end = -1
# 依次与目标值进行比较
for i in range(l, u+1):
if nums[i] == target:
start = min(start, i)
end = max(end, i)
return (start, end)
# 递归结束条件2
if nums[l] == nums[u]: # 数组首尾元素相等,则中间元素也都相等
if nums[l] == target:
return (l, u)
else:
return (max_len, -1)
# 开始二分法
mid = int((l+u)/2)
if nums[mid] == target: # 中位数等于目标值
# 寻找左半部分的首尾位置
start1, end1 = binary_search(nums, l, mid, target, max_len)
# 寻找右半部分的首尾位置
start2, end2 = binary_search(nums, mid, u, target, max_len)
# 两个首尾位置比较大小
start = min(start1, start2)
end = max(end1, end2)
return (start, end)
elif nums[mid] > target: # 目标值小于中位数
# 寻找左半部分的首尾位置
return binary_search(nums, l, mid, target, max_len)
else:
# 否则,寻找右半部分的首尾位置
return binary_search(nums, mid, u, target, max_len)
if not nums or target < nums[0] or target > nums[-1]:
return [-1, -1]
max_len = len(nums)
start, end = binary_search(nums, 0, max_len-1, target, max_len)
if start == max_len:
start = -1
return [start, end]
if '__main__' == __name__:
nums = [5,6,7,8,8,10]
target = 10
print(searchRange(nums, target))