LeetCode C++ 33. Search in Rotated Sorted Array【二分】中等

myRealization發表於2020-10-21

You are given an integer array nums sorted in ascending order, and an integer target .

Suppose that nums 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] ).

If target is found in the array return its index, otherwise, return -1 .

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

Example 3:

Input: nums = [1], target = 0
Output: -1

Constraints:

  • 1 <= nums.length <= 5000
  • -10^4 <= nums[i] <= 10^4
  • All values of nums are unique.
  • nums is guranteed to be rotated at some pivot.
  • -10^4 <= target <= 10^4

題意:給出一個升序排序的陣列和一個整數,這一陣列在未知的某個點上進行了旋轉,如 [1,2,3,4,5,6,7] 可能變為 [4,5,6,7,1,2,3] 。然後需要在陣列中搜尋目標值,如果存在則返回它的位置。


解法1 順序搜尋

完全沒有利用到陣列的特徵,直接進行最簡單的順序搜尋, O ( n ) O(n) O(n) 的時間複雜度:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        for (int i = 0; i < nums.size(); ++i) if (nums[i] == target) return i;
        return -1;
    }
};

效率如下,比較感人:

執行用時:16 ms, 在所有 C++ 提交中擊敗了17.24% 的使用者
記憶體消耗:11.3 MB, 在所有 C++ 提交中擊敗了5.21% 的使用者

解法2 找到旋轉點

我們可以找到那個旋轉點,不是進行陣列的恢復(太浪費時間了),而是經過判斷,對旋轉點的一邊進行二分搜尋,得到結果。這一演算法的整體時間複雜度是 O ( n ) O(n) O(n) ,沒有實質的改進。暫時不想寫程式碼。


解法3 利用陣列的特徵

對於旋轉陣列,如果將其一分為二,則其中一定有一個是有序的,另一個可能有序也可能無序。對有序部分用二分查詢,無序部分再一分為二……這樣迴圈。具體程式碼如下:

class Solution {
public:
    int search(vector<int>& nums, int target) { 
        int lo = 0, hi = nums.size() - 1;
        while (lo <= hi) {
            int mid = lo + (hi - lo) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] < nums[hi]) { //右半段是有序的
                if (nums[mid] < target && target <= nums[hi]) lo = mid + 1; //對右半段二分搜尋
                else hi = mid - 1; //右半段有序,但不在右半段的範圍內,因此對左半段搜尋
            } else { //左半段有序
                if (target >= nums[lo] && target < nums[mid]) hi = mid - 1; //對左半段二分搜尋
                else lo = mid + 1; //左半段有序,但不在左半段的範圍內,因此對右半段搜尋
            }
        }
        return -1;
    }
};

提交後效率如下:

執行用時:4 ms, 在所有 C++ 提交中擊敗了82.70% 的使用者
記憶體消耗:11.2 MB, 在所有 C++ 提交中擊敗了5.21% 的使用者

遞迴版程式碼如下:

class Solution {
private:
    int binarySearchInRotatedSortedArray(const vector<int>& a, int l, int r, int t) {
        if (l > r) return -1;
        int mid = l + (r - l) / 2;
        if (a[mid] == t) return mid;
        else if (a[mid] < a[r]) { //右半段有序
            return (a[mid] < t && t <= a[r]) ?
                binarySearchInRotatedSortedArray(a, mid + 1, r, t) : 
                binarySearchInRotatedSortedArray(a, l, mid - 1, t);
        } else { //左半段有序
            return (t < a[mid] && t >= a[l]) ?
                binarySearchInRotatedSortedArray(a, l, mid - 1, t) :
                binarySearchInRotatedSortedArray(a, mid + 1, r, t);
        }
    }
public:
    int search(vector<int>& nums, int target) { 
        return binarySearchInRotatedSortedArray(nums, 0, nums.size() - 1, target);
    }
};

遞迴版的效率低一些:

執行用時:8 ms, 在所有 C++ 提交中擊敗了45.60% 的使用者
記憶體消耗:11.4 MB, 在所有 C++ 提交中擊敗了5.21% 的使用者

相關文章