LeetCode 33, 81. Search in Rotated Sorted Array I+II

Search in Rotated Sorted Array

Binary Search的变种。由于rotated的存在,直接A[mid]<key的判断并无法解决继续搜索哪一半边。

思路是分情况,分为左半边有序还是右半边有序,再细分是继续搜索左半侧还是右半侧。由于涉及a[mid]和a[low],a[high]的比较,用闭区间比较好。    

由于没有重复元素,上图 a[low]<a[mid]>a[high],下图 a[low]>a[mid]<a[high]。我们可以根据上述条件判断是左边有序还是右边有序。

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

由于mid是向下取整,其中 nums[low]==nums[mid] 归到了 nums[low]<nums[mid]。 由于没有重复的元素,nums[low]==nums[mid] 只可能在搜索区间只有两个元素的时候出现。此时,如果左边元素就是target,之前的语句就会return,因此一定不是第一个元素,low=mid+1,因此可以归到 nums[low]<nums[mid] 中。二分的边界情况还是要小心。

 

如果依旧向下取整,a[mid]可能等于a[low],但是a[mid]是绝对不可能等于a[high]的(除非只有一个元素时)。下面这样写就可以规避掉 a[mid]==a[high] 的可能性。对followup写起来更方便。

class Solution {
public:
    bool search(vector<int>& a, int target) {
        int low=0, high=a.size()-1; //[low,high]
        while (low<=high){
            int mid=(low+high)/2;
            if (a[mid]==target) return true;
            if (a[mid]<a[high]){ //right side is in order
                if (a[mid]<target && target<=a[high]) low=mid+1;
                else high=mid-1;
            }else{ //left side is in order
                if (a[low]<=target && target<a[mid]) high=mid-1;
                else low=mid+1;
            }
        }
        return false;
    }
};

此外,

if (a[low]<=target && target<a[mid]) high=mid-1;
if (a[mid]<target && target<=a[high]) low=mid+1;

的符号一定要小心,如果等号位置不对,解就不在搜索区间里了。

二分时间复杂度 O(logn)

 

Search in Rotated Sorted Array II

虽然有重复元素在,但是思路和上一题是一样的。唯一的区别就是,当 a[mid]==a[high] 时,说明有duplicate了,我们直接 --high,反正还有 a[mid] 在,直接把high的元素去掉缩小范围继续二分即可。

class Solution {
public:
    bool search(vector<int>& a, int target) {
        int low=0, high=a.size()-1; //[low,high]
        while (low<=high){
            int mid=(low+high)/2;
            if (a[mid]==target) return true;
            if (a[mid]<a[high]){ //right side is in order
                if (a[mid]<target && target<=a[high]) low=mid+1;
                else high=mid-1;
            }else if (a[mid]>a[high]){ //left side is in order
                if (a[low]<=target && target<a[mid]) high=mid-1;
                else low=mid+1;
            }else{ // a[mid]==a[high]
                --high;
            }
        }
        return false;
    }
};

时间复杂度 O(logn) on average,O(n) worst case.

 

posted @ 2018-06-01 23:02  約束の空  阅读(123)  评论(0编辑  收藏  举报