【Python Leetcode】153. Find Minimum in Rotated Sorted Array

本文介绍了如何使用二分查找算法在经过n次旋转的有序数组中寻找最小元素,复杂度为O(logn)。通过分析数组在旋转后的特性,确定了三种关键情况并给出相应处理策略。具体实现包括代码示例,展示了不同情况下如何调整查找窗口,以及特殊情况的处理。此外,还提供了优化过的代码,进一步提高了查找效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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.

从小到大排列的数组在经过n次回转之后,以O(log n)复杂度找到其最小元素。每一次回转会将数组最后一个元素放入数组首位,其余元素顺次往后一位。

Constraints 条件限制:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • All the integers of nums are unique.
  • nums is sorted and rotated between 1 and n times.

思路:二分法查找

O(log n)复杂度首先想到二分法。可将数组index与元素值的关系看作分段函数,在每一段上单调递增,且第二段函数的最大值小于第一段函数的最小值。
分段函数实例
设发f(m)为函数最小值。设a为查找窗口的左端,b为窗口右端(b>a),c为ab中值 (c=(a+b)/2)。讨论f( c)与f(a)及f(b)关系,则有:

  • 【情况一】f(a)<f( c)且f(b)<f( c): a与c在第一段函数上,b在第二段函数上,c<m<=b.
  • 【情况二】 f(a)>f( c)且f(b)>f( c): b与c在第二段函数上,a在第一段函数上,a<m<=c.
  • 【情况三】f(a)<f( c) < f(b): abc均在第一段或第二段函数上,m<=a或m>=b.
  • 【情况四】f(a)=f( c): 由于int类型整除的特性,当b-a<2时,a=c. 由于contraints里规定数组中元素unique,当且仅当a=c时f(a)=f( c).

初始,令a=0, b=n-1.

  • 【情况一】:将窗口左端缩小,a=c.

  • 【情况二】:将窗口右端缩小, b=c.

  • 【情况三】:在初始情况下出现f(a)<f( c)<f(b),说明该数组经过n次rotation后恢复单调递增,则f(a)为最小值,直接返回。非初始情况下,可比较nums[0]与nums[a]的大小:

    • nums[0]<=nums[a]: 返回nums[0]
    • nums[0]>nums[a]: m>=b且窗口搜索不足以找出最小值,遍历b到n-1之间的元素返回最小值(一般仅需遍历1-2个元素)。
  • 【情况四】:比较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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值