1. 程式人生 > 實用技巧 >LeetCode154. 尋找旋轉排序陣列中的最小值 II

LeetCode154. 尋找旋轉排序陣列中的最小值 II

經過旋轉後的陣列,滿足這樣一個性質,最小值右邊的元素,都大於等於最小值(因為這題有重複元素,所以有可能等於),最小值左邊的元素,都大於等於最小值。

所以每一次二分,我們可以與當前區間的最左邊或最右邊進行比較,確定最小值的位置。

這裡我們每次將區間中點的值nums[mid]與區間右端點nums[right]進行比較。

  1. 如果nums[mid] < nums[right],這說明區間右半部分是升序的,那麼最小值肯定不在這部分,最小值最大隻能是nums[mid],所以讓right = mid;

  2. 如果nums[mid] < nums[right],這說明區間右半部分不是升序的,說明陣列的旋轉位置就在右半部分,最小值肯定在mid + 1 ~ right這部分,所以讓left = mid + 1;

  3. 如果nums[mid] == nums[right],這有幾種情況,一種陣列全都是相同元素,一種是在mid和right之間先上升後下降,後者mid和right之間先下降後上升,不管怎樣,我們還需要在這個區間內繼續尋找元素,
    只不過現在不能直接折半了,而只能讓right -= 1(或--right),也就是刪去一個重複元素,繼續判斷nums[mid]和nums[right](這裡的right是剛才那個right的前一個位置)的大小關係。

因為第三種情況最壞情況下每次只能去掉一個元素,所以這題最壞情況下的時間複雜度是O(n)。

程式碼如下:

class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while(left < right) {
            int mid = (left + right) >> 1;
            if(nums[mid] < nums[right]) {
                right = mid;
            } else if(nums[mid] > nums[right]) {
                left = mid + 1;
            } else {
                --right;
            }
        }
        return nums[left];            //這裡nums[left]和nums[right]都可以
    }
};