【剑指offer】6.旋转数组的最小数字[by Python]

本文探讨了寻找旋转数组中最小值的四种高效算法,包括暴力解法、二分法、递归优化及非递归版本,详细解析每种方法的优劣及适用场景。

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

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

解题思路

思路1

暴力解法:根据给定的数组特点,从左到右遍历数组元素,当首次遇到数组中某个元素比上一个元素小时,该元素就是我们需要的元素。

python代码
defminNumberInRotateArray(self, rotateArray):
    if not rotateArray:
        return 0
    num = rotateArray[0]
    for i in range(1,len(rotateArray)):
        if rotateArray[i] >= num:
            num = rotateArray[i]
        else:
            return rotateArray[i]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
思路2

思路1的做法太无脑,时间复杂度O(N)。旋转数组也算是一种排序数组,可以用二分法解题,使时间复杂度最低控制在O(lgN)。
由于最近递归用的比较多,本能的就想通过递归求解该题。具体思路是用变量mid定位到数组的中间位置,将数组头部的值与mid处的值进行比较,不断缩小数组。这里有两个需要注意的点:
1. 由于是旋转数组,缩小到最小的数组大小为2,且数组中第一个元素为数组中值最大的元素,第二个元素是数组中值最小的元素,最后返回第二个元素。
2. 当数组中包含重复元素,具体到代码中是:当mid处的值等于数组头部的值时,无法判断最小值位于mid左侧还是右侧,此时只能采取遍历的方式。

Python代码
def minNumberInRotateArray(self, rotateArray):
    if not rotateArray:
        return 0
    if len(rotateArray)==2:
        return rotateArray[1]

    mid = int(len(rotateArray)/2)
    if rotateArray[mid] > rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[mid:])
    elif rotateArray[mid] < rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[:mid+1])
    else:
        for i in range(1,len(rotateArray)):
            if rotateArray[i] < rotateArray[0]:
                return rotateArray[i]
        return rotateArray[0]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
思路3

思路3属于思路2的小优化,可以缩短代码的长度,但不能改变代码的时间复杂度。具体来说,当mid处的值等于数组头部的值时,即当代码需要遍历时,可用一行代码代替for循环:

def minNumberInRotateArray(self, rotateArray):
    if not rotateArray:
        return 0
    if len(rotateArray)==2:
        return rotateArray[1]

    mid = int(len(rotateArray)/2)
    if rotateArray[mid] > rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[mid:])
    elif rotateArray[mid] < rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[:mid+1])
    else:
        return self.minNumberInRotateArray(rotateArray[1:])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
思路4

由于每次递归都需要传入数组,这无疑更占用存储空间,特别当数组特别长时。最后给出该方法的非递归版本,只有一个数组不变,变化的只有指向数组的指针指向。

def minNumberInRotateArray(self, rotateArray):
    left = 0
    right = len(rotateArray)-1
    while left < right:
        mid = int((left+right)/2)
        if rotateArray[mid] > rotateArray[right]:
            left = mid+1
        elif rotateArray[mid] < rotateArray[right]:
            right = mid
        else:
            right -= 1
    return rotateArray[left]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

虽然思路4代码简短,时间复杂度和空间复杂度都比较低,但是如果稍微不注意,还是会掉到小坑里,比如如果用mid处的值和数组左边的值比较,会有什么不同;else语句中如果不让right处的指向左移一位,而是让left处的指针右移一位会怎么样,都是需要稍加留意的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值