1. 程式人生 > 其它 >劍指offer11. 旋轉陣列的最小數字

劍指offer11. 旋轉陣列的最小數字

把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。例如,陣列 [3,4,5,1,2] 為 [1,2,3,4,5] 的一個旋轉,該陣列的最小值為1。

輸入:[3,4,5,1,2]
輸出:1

思路

這道題簡單的地方在於一眼能看出來是二分,難點在於特殊情況的考慮。
旋轉操作讓這個陣列可以分成兩個遞增的陣列,並且右邊那個要更小。

最簡單的情況,假設沒有重複元素,左邊陣列的開頭設為start, 那麼我們始終有: e l e m e n t [ r i g h t ] < s t a r t element[right] < start

element[right]<start

我們要找的拐點就是小於start的第一個數。這直接套二分查詢就行。

特殊情況1:

搬了所有元素或沒有搬任何元素,這樣不存在兩個子陣列,這種情況,最右會大於最左(在沒有重複元素時)。

特殊情況2:

存在相等元素:

  • 相等元素在非切割點,這種氣勢不需要管,因為不影響我們最初的假設即 element[right] < start,譬如[3,4,5,5,1,2]
  • 切割旋轉點本身就在一系列相等元素中。譬如[1,2,2,2,4]–>[2,2,4,1,2]
    • 這種情況下,不符合 e l e m e n t [ r i g h t ] < s t a r t element[right] < start
      element[right]<start
      ,當一個元素=start的時候,無法判斷它在左陣列還是右陣列
    • 我對於這種情況的處理採取去重,也就是這個重複的元素k在最開始讓它在左側陣列先消失。這對於找最小元素是沒有影響的,反正右陣列依然保留了這個k。 如果k是最小,可以在右陣列找到;如果k不是最小,可以在有陣列找到比k小的存在。如下所示,上下兩個找旋轉點是等價的。
      [1,2,2,2,4] --> 旋轉–> [2,2,4,1,2]
      [1,2,4] --> 旋轉 -->[4,1,2]

程式碼:

lass Solution {
public:
    int minArray(vector<int>& numbers) {
        int left = 0;
        int right =numbers.size()-1;    
        // 去除左邊和最右重複的元素
         while(left < right && numbers[left] == numbers[right])
            left ++;
        int start = numbers[left];
  
        //最小值在旋轉部分的開頭,說明沒有旋轉
        if(numbers[right]>numbers[left])
            return start;
       
        while(left < right){
            int mid = (left + right)/2;
            int val = numbers[mid];
            if(mid-1>=0 && val < numbers[mid-1]) // 確定找到拐點
                return val;
            if(val>=start){
                left = mid+1;
            }
            else if(val < start){
                right = mid-1;
            }
           
        }
        return numbers[left];
    }
};