'''
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
!!! 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
'''
# todo 场景1: "单次搜索"
def search_1(nums, target):
left = 0
right = len(nums) - 1
while left <= right: # 这里不用left < right 会报错, left <= right 确保最后一次迭代能够处理仅剩两个元素的情况
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
if nums[mid] >= nums[left]: # 截至到[mid]都是升序,表明mid左半部分有序
if nums[left] <= target < nums[mid]:
right = mid - 1
else: # 这边用else涵盖其他,避免了mid右侧不一定有序的问题 456 7123 (target:5)
left = mid + 1
else: # 从[mid]向后都是升序,表明mid右半部分有序
if nums[mid] < target <= nums[right]:
left = mid + 1
else: # 这边用else涵盖其他,避免了mid左侧不一定有序的问题 45671 23 (target:2)
right = mid - 1
return -1
# 场景1 测试用例
nums = [4, 5, 6, 7, 0, 1, 2]
target = 0
print(f"target:{target} --> index:{search_1(nums, target)}")
# todo 场景2: "多次搜索"
def findMinIndex(nums):
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
if nums[mid] > nums[right]: # 最小值在右半部分
left = mid + 1
else: # 最小值在左半部分
right = mid
return left
def searchWith_K(nums, target, k):
if not nums:
return -1
# 二分搜索
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
# 把索引映射回原始数组(即初始的Index)--> 调整回有序状态数组 --> 二分查找
real_mid = (mid + k) % len(nums)
if nums[real_mid] == target:
return real_mid
if nums[real_mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# 场景2 测试用例
# nums = [4, 5, 6, 7, 0, 1, 2]
nums = [0, 1, 2, 4, 5, 6, 7]
targets = [0, 5, 2, 1, 3]
k = findMinIndex(nums) # 计算k (pivot) -- 叫旋转点也可以
print(f"旋转点:{k}")
for target in targets:
print(searchWith_K(nums, target, k)) # 复用 k,提高效率
关键:
real_mid = (mid + k) % len(nums) ---> 映射回原数组 ---> 有序状态 ---> 使用二分查找
(所有数字都是Index, 带进array看)
ps.根据具体使用场景选择不同的搜索方式