思路一:二分查找
- 最小值即旋转点,旋转点左边的数都大于nums[0],右边都小于nums[0]
- 取mid,若mid大于数组第一个数,即左半边是顺序,在右边寻找旋转点,否则在左边寻找
class Solution:
def findMin(self, nums: List[int]) -> int:
if len(nums)==1:
return nums[0]
left,right=0,len(nums)-1
#右边数大于第一个数,说明有序
if nums[right]>nums[0]:
return nums[0]
while left<=right:
mid = left + (right - left) // 2
# mid左右存在逆序
if nums[mid]>nums[mid+1]:
return nums[mid+1]
if nums[mid-1]>nums[mid]:
return nums[mid]
#左边顺序,在右边找
if nums[mid]>nums[0]:
left=mid+1
# 否则在左边找
else:
right=mid-1
思路二:优化(快很多)
合并一些情况,只和最右值对比:
如果中值 < 右值,右边顺序,则最小值在左半边,可以收缩右边界。
[1,(2),3,4]
[3,4,5,(1),2]
如果中值 > 右值,左边顺序则最小值在右半边,可以收缩左边界。
[3,4,(5),1,2]
class Solution:
def findMin(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
if nums[mid] > nums[right]:
# 因为中值 > 右值,中值肯定不是最小值,左边界可以跨过mid
left = mid + 1
else:
# 因为中值 < 右值,中值也可能是最小值,右边界只能取到mid处
right = mid
return nums[left]
也可以通过比较mid与left来解决问题。
不直接找最小值,而是先找最大值,最大值向右移动一位就是最小值了(需要考虑最大值在最右边的情况,右移一位后对数组长度取余)。
最大值偏右,可以通过比较mid与left来找到最大值,。
class Solution:
def findMin(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right + 1) //2
#中值大于左值,左边顺序,在右边寻找,不能跨越mid
if nums[left] < nums[mid]:
left = mid
elif nums[left] > nums[mid]:
right = mid - 1
return nums[(right + 1) % len(nums)]