详解 剑指offer 11.旋转数组的最小数字

题目要求:

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:1≤n≤100001 \le n \le 100001≤n≤10000,数组中任意元素的值: 0≤val≤100000 \le val \le 100000≤val≤10000

要求:空间复杂度:O(1) ,时间复杂度:O(logn)

牛客链接:https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?

解析:

1.最简单的方法就是遍历一遍,但是遍历一遍的时间复杂度为O(N),不符合题目的要求。

2.题目中说了是一个非降序数组(可能升序,可能是所有元素相同的数组),将它最开始的几个元素般到末尾,变成一个旋转数组,比如元数组是[1,2,3,4,5],变成了[4,5,1,2,3];从这个例子中,我们可以发现两个规律:

  1. 最大值的后一位就是最小值。
  2. 最左边的元素大小一定大于等于最右边的元素大小。

3.设指向最左边的元素的指针为 left, 指向最右边的指针为 right,mid为指向中间元素的指针。

法一:把mid指向的值和left值进行比较

1. 如果a[mid]>a[left] 说明在区间[mid,left]中是一个递增的过程,也就是说最大值所在的位置肯定>=mid;根据第一条规律,最小值所在位置是>mid; 所以,left=mid+1;

2.如果a[mid]<a[left] 说明在区间[mid,left]中存在最小值改变了递增,所以,end=mid;

3.如果a[mid]==a[left],那么可以对left进行++的操作,因为mid和left指向的值是相同的,所以就算left指向的是最小值,区间减小后,也是可以取到mid上的最小值。

4.循环结束条件,根据上面的规律一:a[left]>=a[right],这条语句是为了避免两种情况;情况一:如果测试用例一开始给定的就是一个递减的数组,那么可以直接就不进行循环,返回第一个元素的值也就是最小值;情况二:刚缩小完的范围恰好就是一个递增的数组,那么mid指向的值必然是大于left,所以此时在执行 l=mid+1就会把最小值排除在外。在整个循环过程中 l < r。

具体代码实现:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.empty())
            return 0;
        int l=0;
        int r=rotateArray.size()-1;
        int mid=0;
        while(rotateArray[l]>=rotateArray[r]&&l<r)
        {
            mid=(l+r)>>1;
            if(rotateArray[mid]>rotateArray[l])
                l=mid+1;
            else if(rotateArray[mid]<rotateArray[l])
                r=mid;
            else
                l++;
        }
        return rotateArray[l];
    }
};

法二: 把mid指向的值和right指向的值进行比较

1.这个方法比起前一个方法更加简单,因为这个方法不需要判断a[left]>=a[right];因为当范围[left,right]刚好是一个递增的数组时,此时的mid是小于right,执行r=mid的指令,最小值不会被排除掉。

具体代码实现:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.empty())
            return 0;
        int l=0;
        int r=rotateArray.size()-1;
        int mid=0;
        while(l<r)
        {
            mid=(l+r)>>1;
            if(rotateArray[mid]>rotateArray[r])
                l=mid+1;
            else if(rotateArray[mid]<rotateArray[r])
                r=mid;
            else
                r--;
        }
        return rotateArray[l];
    }
};

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

年轻人江老Der

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值