旋转数组是指在原有顺序数组基础上,以某个未知点进行了旋转。以升序数组为例,其旋转后有三种基本形态(见下图,图中虚线为数组中心位置):
情况一:未旋转
情况二:旋转点位于中心位置右侧
情况三:旋转点位于中心位置左侧。
利用二分法可以以
O
(
l
o
g
n
)
(
O(logn)(
O(logn)(的时间复杂度在旋转数组中进行搜索。解决此类的问题,需要注意如下几点:
(1)除情况1外,旋转数组以最高点为分割,左右两侧的部分从左到右都为升序(原始数组为升序数组);
(2)通过mid点与low点或high点的大小,来进行形态的分类讨论;
(3)注意边界条件。比如在二分法中,通过mid=(low+high)/2迭代终点时,若原数组长度为2时,mid和low是重叠的,因此要注意mid-1的溢出。同时在不同问题中mid可能保持原指针,也可能需要±1.
下面以两个例子来简单介绍下旋转数组的搜索问题。
【问题一】搜索某值是否在旋转数组(升序)中
def findRotateArray(array, num):
if not array:
return 0
lo, hi = 0, len(array)-1
while lo <= hi:
mid = lo + (hi-lo)//2
if array[mid] == num:
return mid
elif array[mid] > array[lo]:
if array[lo] <= num < array[mid]:
hi = mid - 1
else:
lo = mid + 1
else:
if array[mid] < num <= array[hi]:
lo = mid + 1
else:
hi = mid - 1
return -1
【问题二】寻找旋转数组(升序)中的最小元素
def minNumberInRotateArray(rotateArray):
if not rotateArray:
return 0
lo, hi = 0, len(rotateArray) - 1
while lo < hi:
mid = lo + (hi - lo) // 2
if rotateArray[mid] > rotateArray[hi]:
lo = mid + 1
elif rotateArray[mid] == rotateArray[hi]: # 注意mid可能和lo为同一个数,所以应当和high对比
hi -= 1
else:
hi = mid
return rotateArray[lo]