【剑指Offer-查找和排序】面试题11:旋转数组中的最小数字

题目描述

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

思路

根据定义,可以把旋转数组a[]看做是两个递增数组的拼接,且前一个递增数组中的元素值大于等于后一个递增数组中的元素值。递增数组的查找可以通过二分查找来实现。类似于二分查找,首先设置两个指针idx1和idx2表示查找的范围为[idx1, idx2]。查找范围中间的元素为mid=(idx1+idx2)/2,如果a[mid]>=a[idx1],则说明mid在第一个递增数组中,因为第一个递增数组中的元素值大于第二个递增数组中的元素值,所以最小值在第二个递增数组当中,此时设置idx1=mid,缩小查找范围;如果a[mid]<=a[idx2],则说明mid在第二个递增数组当中,则最小值在mid的左边,所以设置idx2=mid来缩小查找范围。这样,第一个指针总是指向前一个递增数组中的元素,而第二个指针总是指向后一个递增数组中的元素,这两个指针最终会指向相邻的元素。所以算法的终止条件就是idx1+1==idx2,此时idx2指向的元素就是旋转数组的最小元素。

代码如下:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int idx1 = 0;
        int idx2 = rotateArray.size()-1;
        while(rotateArray[idx1]>=rotateArray[idx2]){
            if(idx1+1==idx2)
                return rotateArray[idx2];
            int mid = (idx1 + idx2) /2;
            if(rotateArray[mid]>=rotateArray[idx1])
                idx1 = mid;
            else if(rotateArray[mid]<=rotateArray[idx2])
                idx2 = mid;
        }
        return rotateArray[idx1]; //此时说明整个数组就是递增的,第一个元素就是最小元素
    }
};

在前面的代码中,当idx1和mid指向的元素相同时,我们认为最小数字在idx1的后面,这其实是不一定的。例如:

也就是说,当idx1、idx2和mid指向的元素都相同时,我们是无法确定最小的数字是位于前面的子数组还是后面的子数组,也无法移动指针来缩小查找范围。针对这种情况,应该使用顺序查找来在[idx1,idx2]之间查找最小值,改进后的代码如下:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int idx1 = 0;
        int idx2 = rotateArray.size()-1;
        while(rotateArray[idx1]>=rotateArray[idx2]){
            if(idx1+1==idx2)
                return rotateArray[idx2];
            int mid = (idx1 + idx2) /2;
            if(rotateArray[idx1]==rotateArray[mid]&&rotateArray[mid]==rotateArray[idx2]){
                int ans = rotateArray[idx1];
                for(int i=idx1+1; i<=idx2; i++){
                    if(ans>rotateArray[i])
                        ans=rotateArray[i];
                }
                return ans;
            }
            if(rotateArray[mid]>=rotateArray[idx1])
                idx1 = mid;
            else if(rotateArray[mid]<=rotateArray[idx2])
                idx2 = mid;
        }
        return rotateArray[idx1];
    }
};

两份代码在牛客网均可以通过。

posted @ 2020-02-28 21:34  Flix  阅读(139)  评论(0编辑  收藏  举报