剑指 Offer 11. 旋转数组的最小数字

description

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

示例 1:

输入:[3,4,5,1,2]
输出:1

示例 2:

输入:[2,2,2,0,1]
输出:0

分析

这道题刚开始看到时没有弄懂意思,理解复杂了,其实就是将一个递增排序数组开头的任意个元素挪到数组尾部,查找旋转后的数组中最小值的问题。
首先想到的方法可能是暴力,但效率过低。其次,我们看到递增排序数组这几个字时,应该想到二分的方法,这也是看到排序数组后应该第一个想到的方法。
我们可以将数组分为两部分,两个部分均为递增有序数组(有可能一个数组元素个数为n,一个元素个数为0),此时数组会存在峰值和低谷值。低谷值就是原数组的第一个值即要找的最小值,峰值就是原数组的最后一个值即最大值。所以问题转化为了找到原始数组的第一个值,其实也就是前后两个数组的“旋转点”,“旋转点”前面的即为峰值,“旋转点”后面的即为目标最小值。

在这里插入图片描述

解法0:暴力

从数组下标0开始遍历,比较当前元素和后一个元素的大小关系:
如果当前元素>后一个元素,后一个元素即为要找的最小值,返回
如果没找到符合条件的元素,则下标为0的元素即为最小值,返回

解法1:二分法

一般二分法查找过程:
1.找到中间(mid处)的关键字
2.比较查找的关键字与中间处的关键字大小关系
3.如果相等则已找到
4.如果查找的关键字小于中间的关键字,则在前半部分进行同样过程
5.如果查找的关键字大于中间的关键字则在后半部分进行同样的过程 (递增序列)

要求:顺序存储(需要下标),元素有序(便于变界)。

回到此题:
现将旋转后的数组分为两个有序数组,我们要通过二分法找到旋转点进而找到最小值,需要比较a[mid] 和a[right]的大小关系:

当无重复值时:
在这里插入图片描述

  • 若a[mid] < a[right] : 则a[mid] 和 a[right]在同一个数组中,mid后的元素是有序的,所以我们到前面去找最小值。
    right = mid
  • a[mid] < a[right] : 则mid后仍是有序的,再到前面去找。
    right = mid
  • a[mid] = 9,a[right] = 3 :a[mid] > a[right],交界点在mid右面。
    left = mid+1
  • left = right 返回a[left]
    在这里插入图片描述
  • 若a[mid] > a[right] : 则a[mid] 和 a[right]在两个数组中,mid前的元素是有序的,所以我们到mid后去找最小值。接下来同上

当有重复值时:如:
在这里插入图片描述
这时,我们需要换种思路,
当a[mid] == a[right]时,我们暴力地将right指针左移(right–),mid也相应移动(mid–)
当mid移动到“3”处,我们比较发现:a[mid] < a[right],所以mid后为有序数组,最小值在前面,所以right = mid。之后按照上述步骤即可求出最小值。

代码实现

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int l = 0, r = numbers.size() - 1;
        while(l < r){
            int mid = l + (r - l) / 2;
            if(numbers[mid] < numbers[r]){//说明mid右侧有序,到左侧去找
                r = mid;
            }
            else if(numbers[mid] > numbers[r]){//说明mid左侧有序,到右侧去找
                l = mid + 1;
            }
            else if(numbers[mid] == numbers[r]){//无法二分,暴力缩小范围
                r--;
            }
        }
        return numbers[r];
    }
};

复杂度

平均时间复杂度:O(logn) (最坏:所有元素相同,O(n))
空间复杂度:O(1)

注:
该题同LeetCode 154题:寻找旋转排序数组中的最小值 II
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值