https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/
知道怎么做,但是思路不清晰,不知道index的停止条件。
note: 只要nums[s] < nums[e] 那么肯定没有rotation。
参考: 结合Find Minimum in Rotated Sorted Array题目一起看
http://bookshadow.com/weblog/2014/11/06/find-minimum-in-rotated-sorted-array-ii/
http://bookshadow.com/weblog/2014/10/16/leetcode-find-minimum-rotated-sorted-array/
http://yucoding.blogspot.hk/2014/10/leetcode-question-find-minimum-in_27.html
理解
在没有重复值的时候,我们可以nums[mid]只有在low == high, 只有一个元素的情况下等于nums[high], 所以这个时候马上就要跳出while low<=high循环了,所以这个时候把等号放在nums[mid] <=nums[high]或者nums[mid] >=nums[high]都是可以的。
但是这里不一样,如果nums[mid] == nums[high]就不知道最小值是在[low:mid]还是在[mid+1:high]中了。例如{3,3,1,3}, low应该等于 mid + 1, 而{1,3,3,3}中的high就应该等于mid - 1.所以这里的BS要把等号的情况单独拿出来。
方法1 含递归
class Solution:
# @param num, a list of integer
# @return an integer
def findMin(self, num):
ans = num[0]
size = len(num)
low, high = 0, size - 1
while low <= high:
mid = (low + high) / 2
ans = min(ans, num[mid])
if num[mid] < num[high]: #min位于上升沿左侧
high = mid - 1
elif num[mid] > num[high]: #min位于左侧上升沿与右侧上升沿之间
low = mid + 1
else: #num[mid] == num[high]的情况下,不知道最小值是在左边还是右边,所以这里直接左右都递归
if low < mid:#这里只有一种情况low == mid, 即搜索范围只有两个或者一个元素,所以这个时候已经用ans = min(ans, num[mid])进行了判断,所以就不用进行这个递归了。这个条件不能去掉?why?再思考
ans = min(ans, self.findMin( num[low : mid + 1] ))
if mid + 1 < high:这里也一样,只有在搜索范围只有两个或者一个元素的是,mid + 1>=high,所以不需要搜索。这个条件不能去掉?why?再思考
ans = min(ans, self.findMin( num[mid + 1 : high + 1] ))
break#注意这里一定要有break
return ans
方法2 返回nums[low],让low指向最小值
这里code中用s表示low,e表示high
这里首先不考虑[s,e]范围内递增的情况,即nums[e]>nums[s],否则直接跳出循环nums[s]即为最小值。另一点就是如果nums[mid] > nums[e] (注意这里没有等于), 注意这里这里mid只可能发生在左边部分,要不在重复值出现的位置,要不就在上升段,那么最小值肯定不会出现在mid这个位置,至多也就是mid + 1, 所以这里可以令s = mid + 1. 如果nums[mid] < nums[e], 注意没有等于,那么mid肯定出现在右边部分,这里不同的一点就是mid可能对应最后的最小值,所以这里可以令e = mid. 如果nums[mid] = nums[e], mid肯定出现在重复区域,这里可以理解为最小值肯定不在s上,所以s可以往前走一步。
再一次强调这里的推断都是在nums[e] <=nums[s]的条件下进行的。
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
s, e = 0, len(nums) - 1
while s < e and nums[s] >= nums[e]:# when rotations。这里不能变成s<=e, 因为在{1}一个元素的情况下,s会越界,使得return nums[s]没有意义。
mid = (s + e)/2
if nums[mid] > nums[e]:
s = mid + 1
elif nums[mid] < nums[e]:#如果mid刚好就是min的时候
e = mid
else:
s += 1## right shift the "left" to narrow the range, which can avoid redundant element.这里不知道最小值是在左边还是右边,所以反正最后也是返回nums[s],所以s前进是可以缩小范围的,一直到[s:e]是个递增区间就找到最小值nums[s]了
return nums[s]
思路3,效率最高,自己重写过
返回一个min ans就行。分三种情况nums[mid] > nums[high], nums[mid] < nums[high], nums[mid] == nums[high] (这里等于的时候,要去掉重复值,一般来说要用一个while来去掉,但是这里外面已经有一个while了,所以这里直接将high-=1就行了。自己可以举例)
class Solution(object):
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
low = 0
high = len(nums) - 1
ans = nums[low]#注意这里也可以用10000初始化。
while low <= high :
mid = (low + high) / 2
ans = min(ans, nums[mid])
if nums[mid] > nums[high]:
low = mid + 1
elif nums[mid] < nums[high]:
high = mid - 1
else:
#这里nums[mid]等于了nums[high],
#并且nums[mid]已经判断过最小值了。
#就要将重复值去掉。通常这里要用一个while循环将重复值去掉。
#但是这里因为外面有一个while,所以直接这里high -= 1就行了。
high -= 1
return ans