剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
class Solution(object):
def minArray(self, numbers):
"""
:type numbers: List[int]
:rtype: int
"""
left,right = 0,len(numbers)-1
while left<right:
mid = (left + right)//2
if numbers[mid] > numbers[right]:
left = mid + 1
elif numbers[mid] < numbers[right]:
right = mid
else:
right -= 1
return numbers[left]
思路·:
二分法,对于本题的旋转数组,左半边和右半边分别有序,最小值在两个有序数组的之间。
思考两个问题
满足什么条件可以确定最小值在右边?
如果索引mid处的值比right处的值要大,说明mid在左半边的升序数组,最小值在mid右边,令left = mid + 1
满足什么条件可以确定最小值在左边?
如果索引mid处的值比right处的值要小,说明mid在右半边的升序数组,最小值可能就在mid处,也可能在mid左边,令right = mid
同样,如果索引mid处的值比left处的值要小,也可以说明mid在右半边的升序数组,同样令right = mid
这两个问题解决后,还要解决最后一个问题,因为数组中可以有重复元素,如果mid处的值和right处的值一样怎么办?这种情况下,mid和right所指的数都有可能是最小值,既然两个都可能是最小值,只要保留一个在查找区间内就可以了,把mid保留,令right = right - 1。