假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -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
解题思路
由于问题给定的时间复杂度要求是O(logn)
级别,所以你当然不能通过直接遍历得到。我们首先想到的是通过二分搜索法,但是这里的二分搜索法需要一些变化。对于第一个例子来说
4 5 6 7 0 1 2
l m r
我们首先计算nums[m]=7
,然后比较nums[m]>=nums[l]
,如果成立,说明[l:m]
这个区间正常。我们先要在[l:m]
这个区间找target
,也就是我们要判断nums[l]<=target<=nums[m]
,如果成立说明在这个区间内,我们让r=m
,否则的话l=m+1
。
4 5 6 7 0 1 2
l m r
回到上一步nums[m]>=num[l]
成立,nums[l]<=target<=nums[m]
也成立,我们将r=m
4 5 6 7 0 1 2
l r
m
nums[m]>=num[l]
成立,nums[l]<=target<=nums[m]
也成立,我们将r=m
4 5 6 7 0 1 2
l
r
m
此时target=nums[m]
,即返回m
。
如果我们发现nums[m]<nums[l]
,说明[m:r]
这个区间正常。例如
5 6 7 0 1 2 4
l m r
我们就要先判断target
是不是在[m:r]
这个区间内(注意这里不是m+1
,我在这里犹豫了很久,如果画图的话很好理解,其实m
就是一个交界处,所以两种情况都会包含),也就是判断nums[m]<=target<=nums[r]
,如果成立l=m+1
,否则的话r=m
。
总体的思路就是先找出中间元素,然后判断左右哪个是标准空间(排好序的空间),接着判断元素是不是在标准空间中(因为这是可以确定的)。接着继续回到之前步骤,直到找到为止。
class Solution:
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if not nums:
return -1
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) // 2
if target == nums[mid]:
return mid
if nums[low] <= nums[mid]:
if nums[low] <= target <= nums[mid]:
high = mid
else:
low = mid + 1
else:
if nums[mid] <= target <= nums[high]:
low = mid
else:
high = mid - 1
return -1
其实就是二分搜索的泛化。
reference:
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!