《剑指offer》面试题11:旋转数组的最小数字(C++实现)

《剑指offer》面试题11:旋转数组的最小数字(C++实现)

题目描述

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

解决思路

最简单的思路,把它看作一个普通的数组,直接遍历求解,是一个O(n)级别时间。复杂度

//运行时间:32ms
//运行内存:692K
class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.size()==0) return 0;
        int min = rotateArray[0];
        for(int i=0;i<rotateArray.size();i++)
            if(min>rotateArray[i]) min=rotateArray[i];
        return min;
    }
};

但是,很显然,这不是最佳的解法,我们没有充分利用旋转数组的这个条件,如何最大限度的活用这个旋转数组的条件,是我们这道题解题的关键。

思路一:二分法查找

这里我们很快会想到,一种活用单调递增顺序的元素查找方法–二分查找法。
虽然这道题不是严格的单调递增序列,但是我们这里仍然可以借用二分查找法的思想。

我们设置left,mid,right分别指向旋转数组最左边,最右边的数字。

(1)当rotateArray[mid]>rotateArray[right],说明最小值一定在[mid+1,right]上
(2)当rotateArray[mid]<rotateArray[right],说明最小值一定在[left,mid]上
(3) 当这两者相等时,我们没有办法,只能顺序搜索。

//运行时间:36ms
//运行内存:620K
class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int length = rotateArray.size();
        if(length == 0) return 0;
        int left = 0;
        int right =length -1;
        int mid;
        while(left<right)
        {    
            mid = left +(right-left)/2;//比(right+left)/2的好处在于防止整型溢出
            if(rotateArray[mid]>rotateArray[right])
                left = mid+1;//这里可以加一是因为至少存在最右的数字比中间数小,所以可以排除
            else if(rotateArray[mid]<rotateArray[right])
                right = mid;//千万注意这里不减1是因为可能出现中间值就是最小值的情况
                            //如果这里减1了,通过用率只有15%
            else return searchMin(rotateArray,mid,right);
        }
        return rotateArray[right];
    }
private: 
    int searchMin(vector<int> &num,int left,int right)
    {   int min = num[left];
         while(left<right)
         {    
            if(min>num[left]) min=num[left];
            left++;
         }
        return min;
    }
    
};

特别注意与二分查找法有两个细微的不一样的地方。

1.在于第二个条件的判断区间不能减1。具体的原因代码中已经详细阐明,这里不再赘述。

2.另外一定要注意我们的while循环条件一定是(left<right),而不是小于等于。

原因是因为,我们循环停止的时候,一定是当指针left和right同时指向那个最小的数字时,这也是我们代码里注解了为什么可以返回left的值,也可以返回right的值。

如果我们在循环条件上是等于,那么在等于的时候会继续循环,然后会发现left=mid=right,然后会执行搜索,造成不必要的浪费。

小结

这道题一定要思路清晰,分析问题,抓住可以用二分法思路的关键。

参考文献

《剑指offer》

牛课网刷题链接link.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值