问题描述
假设一个按升序排序的长度为 n 的数组在 1 到 n 次之间旋转。例如,数组 nums = [0,1,4,5,6,7] 可能会变成:
[4,7,4] 如果旋转了 4 次。
[0,7] 如果旋转 7 次。
请注意,将数组 [a[0],a[1],a[2],...,a[n-1]] 旋转 1 次会导致数组 [a[n-1],a[0],a[n-2]]。
给定排序后的旋转数组nums可能包含重复,返回旋转后该数组第一个最小元素的索引(与旋转次数相同)。
例如:
Input [1,2,3,4] Output: 0
Input [5,4] Output: 2
Input [2,1] Output: 3
Input [1,1] Output: 5
我们可以使用二分搜索来解决它吗?在最坏的情况下,时间复杂度为 O(n),但在一般情况下会好得多。
解决方法
如果左邻居大于当前位置值,则进行二分查找并查看每个位置。然后返回位置索引。否则返回0。
在 Python 中你可以编写
def search_recursive(array,start,end):
if start > end:
return 0
mid = (start + end) // 2
if mid > 0 and array[mid - 1] > array[mid]:
return mid
left = search_recursive(array,mid-1)
right = search_recursive(array,mid+1,end)
if left == 0:
return right
if right == 0:
return left
return min(left,right)
inputs = [[1,2,3,4,4],[5,6,1,[2,1],[1,1]]
for input in inputs:
print(search_recursive(input,len(input)-1))
// Outputs:
// 0
// 2
// 3
// 5
复杂度不好,因为你访问每个元素两次。
另一种方法是使用二分搜索点和一些分支的切割。例如,在 [5,4]
以及值 start=5,mid=1,succ_mid=2
和 end=4
中,您可以将搜索集中到数组 [5,1]
。我的实现如下所示:
def search_recursive(array,start_value,end_value,end):
if start >= end:
return 0
mid = (start + end) // 2
mid_value = array[mid]
succ_mid = mid + 1
succ_mid_value = array[succ_mid]
if start_value > mid_value:
return search_recursive(array,mid_value,mid)
if mid_value > succ_mid_value:
return succ_mid
left = search_recursive(array,mid)
right = search_recursive(array,succ_mid_value,succ_mid,end)
if left == 0:
return right
return min(left,input[0],input[len(input)-1],len(input)-1))
// Outputs:
// 0
// 2
// 3
// 5