假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
请找出其中最小的元素。
你可以假设数组中不存在重复元素。
示例 1:
输入: [3,4,5,1,2]
输出: 1
示例 2:
输入: [4,5,6,7,0,1,2]
输出: 0
解题思路
类似问题
Leetcode 33:搜索旋转排列数组(最详细的解法!!!)
Leetcode 81:搜索旋转排序数组II(最详细的解法!!!)
这个问题主要分成如下三种情况
- l < m i d > r l<mid>r l<mid>r
- l > m i d < r l>mid<r l>mid<r
- l < m i d < r l<mid<r l<mid<r
如果发生旋转的话,那么nums[r]<nums[l]
一定成立(非常容易证明),所以对于第一种情况最小值一定在右侧,所以我们更新low=mid+1
,对于第二种情况最小值一定在左侧或者就在mid
,这要怎么理解呢?如果最小值在右侧的话,说明nums[mid]
比最小值大,那么nums[mid]
一定是大于nums[low]
的(与题目条件不符),所以原结论成立,所以我们更新high=mid
。对于第三种情况,最小值一定是nums[low]
。
但是上述结论仅适用于len(nums)>=3
的情况,对于len(nums)<3
的情况,我们要加以修正。
- l < = m i d > r l<=mid>r l<=mid>r
- l > m i d < = r l>mid<=r l>mid<=r
- l < = m i d < = r l<=mid<=r l<=mid<=r
class Solution:
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) // 2
if nums[low] <= nums[mid]:
if nums[mid] <= nums[high]:
return nums[low]
else:
low = mid + 1
else:
if nums[mid] <= nums[high]:
high = mid
return -1
另外这个问题也可以通过减小选择区间解决,也就是最后剩下的那个元素一定是最小值。思路和上面是一样的,但是我们只取了判断条件的右边一半(当然你也可以去左边的)。
class Solution:
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
low, high = 0, len(nums) - 1
while low < high:
mid = (low + high) // 2
if nums[mid] > nums[high]:
low = mid + 1
else:
high = mid
return nums[low]
但是前面的做法由于添加了剪枝操作,所以速度上比这个更快。
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!