题目:把一个有序数组最开始的若干个元素搬到数组的末尾,称为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组arr = [3, 4, 5, 1, 2]为数组arr = [1, 2, 3, 4, 5]的一个旋转,该数组的最小值为1。
分析:采用二分查找法。旋转数组的特性是数组元素先递增再下降到最小值再递增。下面存在三种边界情况。
(1)数组本身未发生旋转,则最小值为arr[0]。
(2)数组元素值全部相等,则最小值为arr[0]。
(3)数组中大部分值都相等,[1, 0, 1, 1, 1, 1, 1, 1]。
思路:按照二分查找的方法,给定数组arr,首先定义两个变量low(数组第一个元素索引)和high(数组最后一个元素索引)按照题目对旋转规则的定义,第一个元素应该大于或等于最后一个元素的(当旋转个数为0,即没有旋转的时候,要单独处理)。接着遍历数组中间的元素arr[mid],其中mid = low + (high - low)>> 1(防止溢出)。
(1)如果arr[mid] < arr[mid - 1],则arr[mid]一定是最小值。
(2)如果arr[mid + 1] < arr[mid], 则arr[mid + 1]一定是最小值。
(3)如果arr[high] > arr[mid] , 则最小值一定在数组左半部分。
(4)如果arr[mid] > arr[low], 则最小值一定在右半部分。
(5)如果arr[low] == arr[mid] 且arr[high] == arr[mid],则此时无法区分最小值是在数组的左半部分还是右半部分([22222, 2],[2, 1, 2222222222])。在这种情况下,只能分别在数组在左右部分找最小值minL和minR, 然后求出两者的最小值。
code:
(1)
def minNumberInRotateArray(rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
if len(rotateArray) == 1:
return rotateArray[0]
begin, end = 0, len(rotateArray) - 1
while begin <= end:
mid = (begin + end) >> 1#右移动一位相当于除以2
if rotateArray[mid] > rotateArray[end]:
begin = mid + 1
elif rotateArray[mid] < rotateArray[begin]:
end = mid
else:
end -= 1
return rotateArray[begin]
if __name__ == "__main__":
rotateArray = [5, 6, 1, 2, 3, 4]
print(minNumberInRotateArray(rotateArray))
程序运行结果为:
1
def getMin(arr, low, high):
# 如果旋转个数为0,即没有旋转,单独处理,直接返回数组头元素
if arr is None:
print("参数不合法")
return
if low > high:
return arr[0]
# 只还剩下一个元素一定是小值
if low == high:
return arr[low]
mid = low + (high - low) >> 1 # 防止溢出
# 判断arr[mid]是否为最小值
if arr[mid] < arr[mid - 1]:
return arr[mid]
# 判断arr[mid + 1]是否为最小值
elif arr[mid + 1] < arr[mid]:
return arr[mid + 1]
# 最小值一定在数组的左半部分
elif arr[high] > arr[mid]:
return getMin(arr, low, mid - 1)
# 最小值一定在数组的右半部分
elif arr[mid] > arr[low]:
return getMin(arr, mid + 1, high)
# arr[low] == arr[mid] && arr[high] == arr[mid]
# 这种情况下无法确定最小值所在的位置,需要在左右两部分分别进行查找
else:
return min(getMin(arr, low, mid - 1), getMin(arr, mid + 1, high))
if __name__ == "__main__":
arr = [5, 6, 1, 2, 3, 4]
print(getMin(arr, 0, len(arr) - 1))