1. 程式人生 > 實用技巧 >【LeetCode-查詢】旋轉陣列的最小數字

【LeetCode-查詢】旋轉陣列的最小數字

題目描述

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

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

輸入:[2,2,2,0,1]
輸出:0

題目連結: https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/

思路

使用二分查詢來做。陣列可以分為兩個部分,左邊的元素都大於等於右邊的元素。

  • 初始化 left 和 right 兩個指標,left = 0, right = num.size()-1;
  • 如果 left<right,迴圈:
    • mid = (left+right)/2;
    • 如果 nums[mid]>nums[right],說明當前 mid 在左邊,則更新 left = mid+1;
    • 如果 nums[mid]<nums[left],說明當前 mid 在右邊,則更新 right = mid;
    • 如果 nums[mid]==nums[right],此時無法判斷 mid 在左邊還是右邊,則 right-- 縮小範圍;
  • 最後返回 nums[left]。

需要注意的是,我們判斷 nums[mid]>nums[right],而不是 nums[mid]>nums[left],原因是隻靠 nums[mid]>nums[left] 無法判斷 mid 在左邊還是在右邊,而 nums[mid]>nums[right] 可以確定 mid 在哪一邊;使用 nums[mid]<nums[left] 也是一樣的原因。

這題我覺得難點除了上面說的判斷條件之外,還有一點是這題不符合二分查詢的常規寫法。在常規的二分查詢中,如果 right 初始化為 nums.size()-1 的話,迴圈條件應該是 left<=right,right的更新方式應該是 right = right-1,但這題不是,需要注意一下。

程式碼如下:

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int left = 0;
        int right = numbers.size()-1;
        while(left<right){
            if(left==right) return numbers[left];
            int mid = left + (right - left) / 2;
            if(numbers[mid]>numbers[right]) left = mid + 1;
            else if(numbers[mid]<numbers[left]) right = mid;
            else right--;
        }
        return numbers[left];
    }
};
  • 時間複雜度:O(log n)
  • 空間複雜度:O(1)