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