劍指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;
    }
};


面對面試提出的新概念,要多跟面試官溝通,多問幾個問題吧概念弄清楚。
有序數組本身就是旋轉的特例。另外還要考慮數組中有相同數字的特例。如果不能很好地處理這些特例,就很難寫出讓面試官滿意的代碼。



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