剑指Offer_面试题08_旋转数组的最小数字


思路: 如序列 3,4,5,1,2   观察到数组旋转后可以分为两个部分,两个排序的子数组,而且前面的元素都不小于后面数组的元素。而且最小值元素刚好是这两个数组的分界线。

在有序数组中可以使用二分查找法实现O(logn)的查找。本题的数组一定程度上也是有序的,因此可以使用二分法的思想来寻找这个最小元素。


如上图所示,a中:array[mid] >= array[p2]说明mid所指还在左边序列中,p1 = mid;

b中:array[mid] >= array[p2]不成立,则说明mid所指已经在右边序列中,p2 = mid;

c中 p2 - p1 == 1 已经到达分界线即上一次的mid位置


特殊情况:有序数组前面0个元素后移,如 1,2,3,4,5  代码应该要考虑这种情况,因此初始化 mid的时候 将mid初始化为0,如果不执行循环则直接返回array[mid].

超特殊情况

1 0 1 1 1

这种情况下 array[p1] = array[p2] = array[mid] 无法判断mid所指属于左右哪个序列,这个时候不得不采取顺序查找的方式。 这个情况是本题的第二个关键。第一个是二分思想。

牛客网版本代码:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int p = 0;
        int q = rotateArray.size() - 1;
        int mid = 0;    //初始化为0,防止首元素即为最小值
        while(rotateArray[p] >= rotateArray[q])
        {
            //分界点
            if(q - p == 1)
            {
                mid = q;
                break;
            }
            
            mid = (p + q) / 2;
            //元素一样无法二分查找,顺序查找
            if(rotateArray[p] == rotateArray[mid] &&
               rotateArray[q] == rotateArray[mid])
                return minInOrder(rotateArray, p, q);
            
            if(rotateArray[mid] >= rotateArray[q])
                p = mid;
            else
                q = mid;
        }
        return rotateArray[mid];
    }
    //顺序查找最小元素,当序列如1 0 1 1 1时二分查找失效之时
    int minInOrder(vector<int> Array, int low, int high)
    {
        int min = Array[low];
        for(int i = low + 1; i <= high; ++i)
            if(Array[i] < min)
                min = Array[i];
        return min;
    }
};


面对面试提出的新概念,要多跟面试官沟通,多问几个问题吧概念弄清楚。
有序数组本身就是旋转的特例。另外还要考虑数组中有相同数字的特例。如果不能很好地处理这些特例,就很难写出让面试官满意的代码。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章