戴璞微的博客

简单点!做事的动机简单点

剑指offer--旋转数组的最小数字

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


分析:
这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,时间复杂度显然是O(N)。但这个思路没有利用输入数组的特性,我们应该能找到更好的解法。
我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。我们还可以注意到最小的元素刚好是这两个子数组的分界线。我们试着用二元查找法的思路在寻找这个最小的元素。
首先我们用两个指针,分别指向数组的第一个元素和最后一个元素。按照题目旋转的规则,第一个元素应该是大于或者等于最后一个元素的(这其实不完全对,还有特例。后面再讨论特例)。
接着我们得到处在数组中间的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一指针指向该中间元素,这样可以缩小寻找的范围。同样,如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。我们可以把第二个指针指向该中间元素,这样同样可以缩小寻找的范围。我们接着再用更新之后的两个指针,去得到和比较新的中间元素,循环下去。
按照上述的思路,我们的第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最后第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。


代码如下:

public class Solution {

    public int minNumberInRotateArray(int [] array) {
        if ( array == null || array.length < 1){
            return -1;
        }
        int len = array.length;
        int low = 0;
        int high = len - 1;
        int mid = (low + high) / 2;

        //如果首个元素小于最后一个元素,表明数组是排序的。 
        if (array[low] < array[high]){
            return array[low];
        }

        //当low指针与high指针相邻的时候,high指针指向的就是最小元素  
        if ( high - low == 1){
            return array[high];
        }

        while(low < high){
            mid = ( low + high) / 2;
            if(mid==low){//if there are only two elements left  
                return (array[low] < array[high])? array[low] : array[high];  
            }  
            if ( array[mid] >= array[low]){  
                low = mid;
            }else if ( array[mid] <= array[high]){
                high = mid;
            }
        }
        return array[mid];
    }
}

C++代码如下:

class Solution {
    public:
        int minNumberInRotateArray(vector<int> rotateArray) {
            if(rotateArray.size() == 0){
                return 0;
            } 
            int low = 0;
            int high = rotateArray.size()-1;
            //若为升序数组 
            if(rotateArray[low] < rotateArray[high]){
                return rotateArray[low]; 
            }
            //降序数组,两个元素 
            if(high - low == 1){
                return rotateArray[high];
            }
            //降序数组,不止两个元素
            int mid = (low+high)/2;
            while(low < high){
                mid = (low+high)/2;
                if(mid == low){//2个元素 
                    return  (rotateArray[low] < rotateArray[high])?rotateArray[low]:rotateArray[high]; 
                }
                if(rotateArray[mid] >= rotateArray[low]){ 
                    low = mid;
                }else if(rotateArray[mid] <= rotateArray[high]){
                    high = mid;
                }
            }
            return rotateArray[mid];
        }
};
阅读更多
版权声明:本文为博主原创文章,若需转载,请注明http://blog.csdn.net/qq_30091945 https://blog.csdn.net/qq_30091945/article/details/70186895
个人分类: 面试真题在线编程
所属专栏: 剑指offer题解
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭