Problem
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
You may assume no duplicate exists in the array.
- python内置函数min(nums),显然这么解不是本题原意
- 有次序的列表旋转特性:第一个小于尾字符的字符即为旋转点(二分用不到,遍历可用)
- 旋转点比左/右边界都小(二分)
二分应该优于遍历查找
solution
无其他库版本
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
right = len(nums)-1
left = 0
while left < right:
if nums[left] <= nums[right]:
return nums[left]
mid = (left + right)/2
if nums[mid] > nums[right]:
left = mid + 1
else:
right = mid
return nums[left]
if nums[left] <= nums[right]:
return nums[left]
其中这段不是标准的二分,逻辑比较难理解,可以提高执行效率
- 如果是空元素,单元素,无旋转序列直接给出结果
- 每次切分后,根据特性做一个判断,如果left已经到达旋转点,则返回
如何确认return时left元素刚好位于旋转点,而不是旋转点后?
此前left右移,left = mid + 1此时left左边相邻元素为mid元素,已经通过游标右移判断nums[mid] > nums[right],left即为旋转点
nums[mid] > nums[right]
nums[left] = nums[mid+1] <= nums[right]
此前right左移,right = mid ,左移前提nums[mid] <= nums[right], 由于旋转特性right左移范围不会越过旋转点,(其实left右移同样不会越过)
旋转点左边的值肯定大于右边的值,这一特性可以推导出,right左移不会越过旋转点(right =mid,只有mid<= right的时候才可左移),left右移同样不会(left = mid +1, 只有在mid>right的时候才可右移)
discuss solution
class Solution:
def findMin(self, nums):
self.__getitem__ = lambda i: nums[i] <= nums[-1]
return nums[bisect.bisect(self, False, 0, len(nums))]
炫技写法
getitem 鸭子类型,列表特性
此时self[i] = True/False
此时solution instance 具有列表部分特性 , 类似的格式为[False,False,False,True,True,True]
len(nums) 没用默认参数是因为此时,solution instance 还没有 len 方法
bisect.bisect(a, x, lo=0, hi=len(a))
Similar to bisect_left(), but returns an insertion point which comes after (to the right of) any existing entries of x in a.
The returned insertion point i partitions the array a into two halves so that all(val <= x for val in a[lo:i]) for the left side and all(val > x for val in a[i:hi]) for the right side.