LeetCode 33——搜尋旋轉排序陣列

seniusen發表於2018-10-27

1. 題目

2. 解答

2.1. 方法一

直接進行二分查詢,在判斷查詢方向的時候詳細分類。

當 nums[mid] < target 時,

  • 若 nums[left] <= nums[mid],此時,target 一定在nums[mid] 右邊,繼續向右查詢。
  • 若 nums[left] > nums[mid] < nums[right],此時 nums[mid] 兩邊都有較大的元素,我們要進一步確定查詢的方向。
    • 若 target <= nums[right],則向右查詢。
    • 若 target >= nums[left],則向左查詢。
    • 若 nums[right] < target < nums[left],則不存在。

當 nums[mid] > target 時,

  • 若 nums[mid] <= nums[right],此時,target 一定在nums[mid] 左邊,繼續向左查詢。
  • 若 nums[left] <= nums[mid] > nums[right],此時 nums[mid] 兩邊都有較小的元素,我們要進一步確定查詢的方向。
    • 若 target <= nums[right],則向右查詢。
    • 若 target >= nums[left],則向左查詢。
    • 若 nums[right] < target < nums[left],則不存在。

class Solution {
public:
    
       int search(vector<int>& nums, int target) {
        
        if (nums.size() == 0) return -1; // 陣列為空
        
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;

        while(left <= right)
        {
            mid = left + (right - left) / 2;
            
            if (nums[mid] == target)
            {
                return mid;
            }
            else if (nums[mid] < target)
            {
                if (nums[left] <= nums[mid]) // l <= m < r
                {
                    left = mid + 1;
                }
            
                else if (nums[left] > nums[mid] && nums[mid] < nums[right])
                {
                    if (nums[left] <= target)
                    {
                        right = mid - 1;
                    }
                    else if (nums[right] >= target)
                    {
                        left = mid + 1;
                    }
                    else
                    {
                        return -1;
                    }
                }    
            }
            else
            {
                if (nums[mid] <= nums[right]) // = 是隻有一個元素的情況
                {
                    right = mid - 1;
                }
                else if (nums[left] <= nums[mid] && nums[mid] > nums[right]) // = 是因為 mid 等於 left 的情況
                {
                    if (nums[left] <= target)
                    {
                        right = mid - 1;
                    }
                    else if (nums[right] >= target)
                    {
                        left = mid + 1;
                    }
                    else
                    {
                        return -1;
                    }
                } 
            }
        }
        
        return -1;

2.2. 方法二

先利用二分查詢確定轉折點,然後對轉折點兩側的資料分別再進行二分查詢。

當 nums[mid] > nums[right] 時,說明 nums[mid] 在轉折點左側,繼續向右查詢。

當 nums[mid] < nums[right] 時,向左縮小區間,直到 left = right 時,此時 right 即為轉折點的位置。


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

2.3. 方法三

nums[mid] 要麼落在左邊升序的資料區間內,要麼落在右邊升序的資料區間內

當 nums[mid] 在右邊升序的資料區間內

  • 若 nums[mid] < target <= nums[right],則向右查詢;否則向左查詢。

當 nums[mid] 在左邊升序的資料區間內

  • 若 nums[left] <= target < nums[mid],則向左查詢;否則向右查詢。

class Solution {
public:

    int search(vector<int>& nums, int target) {
        
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        
        while(left <= right)
        {
            mid = left + (right - left) / 2;
            
            if (nums[mid] == target)
            {
                return mid;
            }
            else if (nums[mid] < nums[right])  // nums[mid] 在右邊升序的資料區間內    
            {
                if (nums[mid] < target && target <= nums[right]) left = mid + 1;
                else    right = mid - 1;
            }
            else // nums[mid] 在左邊升序的資料區間內    
            {
                if (nums[left] <= target && target < nums[mid]) right = mid - 1;
                else    left = mid + 1;
            }
        }
        
        return -1;
    }
};

獲取更多精彩,請關注「seniusen」!

相關文章