Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:
Notice that rotating an array [a[0], a[1], a[2], …, a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], …, a[n-2]].
Given the sorted rotated array nums of unique elements, return the minimum element of this array.
You must write an algorithm that runs in O(log n) time.
从小到大排列的数组在经过n次回转之后,以O(log n)复杂度找到其最小元素。每一次回转会将数组最后一个元素放入数组首位,其余元素顺次往后一位。
O(log n)复杂度首先想到二分法。可将数组index与元素值的关系看作分段函数,在每一段上单调递增,且第二段函数的最大值小于第一段函数的最小值。
设发f(m)为函数最小值。设a为查找窗口的左端,b为窗口右端(b>a),c为ab中值 (c=(a+b)/2)。讨论f( c)与f(a)及f(b)关系,则有:
初始,令a=0, b=n-1.
【情况一】:将窗口左端缩小,a=c.
【情况二】:将窗口右端缩小, b=c.
【情况三】:在初始情况下出现f(a)
【情况四】:比较f(a)与f(b)返回最小值即可。
代码如下:54ms (14.18%), 13.7mb(56.32%)
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
a = 0
b = len(nums)-1
c = (b+a)/2
if nums[a] < nums[c] and nums[c] < nums[b]:
return nums[a]
while True:
if nums[a] < nums[c] and nums[b]<nums[c]:
a = c
c = (b+a)/2
elif nums[a] > nums[c] and nums[b]>nums[c]:
b = c
c = (b+a)/2
elif nums[a] < nums[c] and nums[c] < nums[b]:
if nums[0]<= nums[a]:
return nums[0]
else:
min = nums[a]
for i in range(b, len(nums)-1):
if nums[i]<min:
min = nums[i]
return min
elif a==c:
if nums[a]<nums[b]:
return nums[a]
else:
return nums[b]
else:
return nums[a]
以下是类似思路,但将n=2,3的情况单独讨论的代码,时间缩短近40%.(31ms, 76.18%; 13.7mb, 56.32%)
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
a = 0
b = len(nums)-1
c = (b+a)/2
if nums[a] <= nums[b]:
return nums[a]
elif b>0 and b<3:
if nums[b-1]>nums[b]:
return nums[b]
else:
return nums[b-1]
while True:
if nums[c] > nums[a]:
a = c
c = (b+a)/2
elif c>=1 and nums[c]<nums[c-1]:
return nums[c]
else:
c -= 1
if c <= 0:
if nums[c]<nums[b]:
return nums[0]
else:
return nums[b]
由于最小值是唯一不满足单调性的解,也可以利用这一特性判断何时返回 (来自官方解法思路)(38ms, 55.3%; 13.9mb, 9.38%):
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
a = 0
b = len(nums)-1
c = (b+a)/2
if nums[a] <= nums[b]:
return nums[a]
elif b>0 and b<3:
if nums[b-1]>nums[b]:
return nums[b]
else:
return nums[b-1]
while b > a:
if nums[c]>nums[c+1]:
return nums[c+1]
if nums[c] > nums[a]:
a = c
c = (b+a)/2
else:
b = c
c = (b+a)/2
return nums[c]