C++實現LeetCode(33.在旋轉有序數組中搜索)

[LeetCode] 33. Search in Rotated Sorted Array 在旋轉有序數組中搜索

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm’s runtime complexity must be in the order of O(log n).

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

這道題讓在旋轉數組中搜索一個給定值,若存在返回坐標,若不存在返回 -1。我們還是考慮二分搜索法,但是這道題的難點在於不知道原數組在哪旋轉瞭,還是用題目中給的例子來分析,對於數組 [0 1 2 4 5 6 7] 共有下列七種旋轉方法(紅色表示中點之前或者之後一定為有序的):

0  1  2   4  5  6  7

7  0  1   2  4  5  6

6  7  0   1  2  4  5

5  6  7   0  1  2  4

4  5  6  7  0  1  2

2  4  5  6  7  0  1

1  2  4  5  6  7  0

二分搜索法的關鍵在於獲得瞭中間數後,判斷下面要搜索左半段還是右半段,觀察上面紅色的數字都是升序的,可以得出出規律,如果中間的數小於最右邊的數,則右半段是有序的,若中間數大於最右邊數,則左半段是有序的,我們隻要在有序的半段裡用首尾兩個數組來判斷目標值是否在這一區域內,這樣就可以確定保留哪半邊瞭,代碼如下:

解法一:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) return mid;
            if (nums[mid] < nums[right]) {
                if (nums[mid] < target && nums[right] >= target) left = mid + 1;
                else right = mid - 1;
            } else {
                if (nums[left] <= target && nums[mid] > target) right = mid - 1;
                else left = mid + 1;
            }
        }
        return -1;
    }
};

看瞭上面的解法,你可能會產生個疑問,為啥非得用中間的數字跟最右邊的比較呢?難道跟最左邊的數字比較不行嗎,當中間的數字大於最左邊的數字時,左半段也是有序的啊,如下所示(藍色表示中點之前一定為有序的):

0  1  2   4  5  6  7

7  0  1   2  4  5  6

6  7  0   1  2  4  5

5  6  7   0  1  2  4

4  5  6  7  0  1  2

2  4  5  6  7  0  1

1  2  4  5  6  7  0

貌似也可以做,但是有一個問題,那就是在二分搜索中,nums[mid] 和 nums[left] 還有可能相等的,當數組中隻有兩個數字的時候,比如 [3, 1],那該去取那一邊呢?由於隻有兩個數字且 nums[mid] 不等於 target,target 隻有可能在右半邊出現。最好的方法就是讓其無法進入左半段,就需要左半段是有序的,而且由於一定無法同時滿足 nums[left] <= target && nums[mid] > target,因為 nums[left] 和 nums[mid] 相等,同一個數怎麼可能同時大於等於 target,又小於 target。由於這個條件不滿足,則直接進入右半段繼續搜索即可,所以等於的情況要加到 nums[mid] > nums[left] 的情況中,變成大於等於,參見代碼如下:

解法二:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) return mid;
            if (nums[mid] >= nums[left]) {
                if (nums[left] <= target && nums[mid] > target) right = mid - 1;
                else left = mid + 1;
            } else {
                if (nums[mid] < target && nums[right] >= target) left = mid + 1;
                else right = mid - 1;
            }
        }
        return -1;
    }
};

到此這篇關於C++實現LeetCode(33.在旋轉有序數組中搜索)的文章就介紹到這瞭,更多相關C++實現在旋轉有序數組中搜索內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: