[python 刷题] 153 Find Minimum in Rotated Sorted Array

[python 刷题] 153 Find Minimum in Rotated Sorted Array

题目:

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:

  • [4,5,6,7,0,1,2] if it was rotated 4 times.
  • [0,1,2,4,5,6,7] if it was rotated 7 times.

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.

一般来说,O(log n) time 是一个比较好的二分算法指向,这道题也是一个二分算法的经典题

这里假设没有被操作过的数组是排好序,每次进行旋转,都会将 list[-1] 移到 list[0],如题目中给的案例 [0,1,2,4,5,6,7],旋转过程为:

  • r = 1

    [python 刷题] 153 Find Minimum in Rotated Sorted Array_第1张图片

    [7,0,1,2,4,5,6]

  • r = 2

    重复该过程:

    [6,7,0,1,2,4,5]

  • r = 3

    [5,6,7,0,1,2,4]

  • r = 4

    如题目所示:[4,5,6,7,0,1,2]

题目给的 input 是已经旋转好的数组,如:nums = [3,4,5,1,2],让找到数组中最小的数字,也就是找到未被旋转的数组中的 l[0]

可以注意到,旋转后的数组还是有规律的:

  • 如果完成了 n 次旋转,即 n = l e n ( n u m s ) n = len(nums) n=len(nums),那么数组其实就是还原成排好序的数组,这个时候的规律为:

    l [ 0 ] < l [ 1 ] < . . . < l [ n − 1 ] l[0] < l[1] < ... < l[n-1] l[0]<l[1]<...<l[n1]

    换言之, l [ 0 ] l[0] l[0] 就是最小的数字

  • 每次旋转都是将数组尾部的数字忘数组头部移动,因此,可以总结出:

    数组中存在一个下标 p p p,满足条件 l [ 0 ] < l [ 1 ] < l [ 2 ] < . . . < l [ p ] l[0] < l[1] < l[2] < ... < l[p] l[0]<l[1]<l[2]<...<l[p],且满足 l [ p ] > l [ p + 1 ] l[p] > l[p+1] l[p]>l[p+1] l [ p + 1 ] < l [ p + 2 ] < . . . < l [ n − 1 ] l[p+1] < l[p+2] < ... < l[n-1] l[p+1]<l[p+2]<...<l[n1] l [ n − 1 ] < l [ 0 ] l[n-1] < l[0] l[n1]<l[0] 这个条件

    也就是说该数组中存在两个递增数组 l 1 ′ l'_1 l1 l 2 ′ l'_2 l2 l 1 ′ l'_1 l1 的最后一个数字比 l 2 ′ l'_2 l2 的第最后一个数字大,而 l 2 ′ l'_2 l2 的第一个数字就是整个数组的最小值

以案例 nums = [3,4,5,1,2] 来说,只要找到一个点 p p p,满足 l [ p + 1 ] < 2 < l [ p ] l[p+1] < 2 < l[p] l[p+1]<2<l[p] 即可。因为 l 1 ′ l'_1 l1 l 2 ′ l'_2 l2 都是递增数组,所以这道题可以用二分算法:

  • l 1 ′ l'_1 l1 中的值一定比 l 2 ′ l'_2 l2 的最后一个数字大
  • l 2 ′ l'_2 l2 中的值一定小于等于 l 2 ′ l'_2 l2 的最后一个数字
class Solution:
    def findMin(self, nums: List[int]) -> int:
        # if the array has been rotated without restore
        # nums[-1] will be smaller than n[0]
        # if n[-1] >= n[0], then it's in sorted
        # some edge cases:
        if nums[-1] >= nums[0]:
            return nums[0]
        if len(nums) == 2:
            return min(nums)
        if nums[-1] < nums[-2]:
            return nums[-1]

        # find the position p, where n[p] < n[-1] < n[p - 1]
        l, r = 0, len(nums) - 1
        target = nums[-1]
        while l <= r:
            m = (l + r) // 2
            if target < nums[m - 1] and target > nums[m]:
                return nums[m]

            if target < nums[m]:
                l = m + 1
            else:
                r = m - 1
        return -1

这个写法能过,并且我个人觉得虽然因为为了找最小数字手动 cover 了一些 edge cases 乱一些,不过理清思路什么的方便一些,个人留着用来推出干净写法

下面是找的别人的干净写法:

class Solution:
    def findMin(self, nums: List[int]) -> int:
        start , end = 0, len(nums) - 1
        curr_min = float("inf")

        while start  <  end :
            mid = (start + end ) // 2
            curr_min = min(curr_min,nums[mid])

            # right has the min
            if nums[mid] > nums[end]:
                start = mid + 1

            # left has the  min
            else:
                end = mid - 1

        return min(curr_min,nums[start])

这里就只是找 min,不用特别在意一些 edge case

你可能感兴趣的:(#,leetcode,python,java,开发语言)