81. Search in Rotated Sorted Array II

仅供自己学习

思路:
思路比较简单,但要注意细节处理。
一开始就是想遍历寻找nums[i]<nums[i-1]获得旋转点,然后对这两侧的数组分别使用二分搜索,但是一直报错,找不到原因。

根据题解二分可知二分的本质是二段性,而非单调性。只要一段满足某个性质,另外一段不满足这个性质就可以用二分。
对于一个递增的数组[1,2,3,4,5,6,7],旋转后[4,5,6,7,1,2,3],前半段满足>=nums[0],但后半段不满足>=nums[0],满足二段性,就可以使用二分找到旋转点。

int l = 0, r = n - 1;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (nums[mid] >= nums[0]) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }

通过if可以找到最后一个大于等于nums[0]的元素。
但如果[0,1,2,2,2,3,4,5]旋转为[2,3,4,5,0,1,2,2]旋转点为第二个2,那么0元素前满足>=nums[0],而0元素后面的2的满足了等于,所以失去了二段性,不能用二分。我们需要通过回复二段性来让这段数组能使用二分。

while(left<right&&nums[0]==nums[right])right--;

通过该代码回复二段性
然后就可以用二分法找到旋转点,因为上述找旋转点的代码是找到最后一个大于nums[0]的元素,所以还要加1才能得到原数组开始的元素。
然后再对这两段调用二分搜索即可,调用的二分也是找到第一个一个大于等于target的二分搜索,如果等于就返回target位置。
代码:

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        int n=nums.size();
        if(n==0) return false;
        if(n==1) return nums[0]==target;
        int left=0,right=n-1;  
        int end=n;
        while(left<right&&nums[0]==nums[right])right--;
        while(left<right){
            int mid =(left+right+1)>>1;
            if(nums[mid]>=nums[0]) {
                left=mid;
            }
            else{
                right=mid-1;
            }
        }
        if(nums[right]>=nums[0]&&right+1<n) end=right+1;
        int res = binary_search(nums,target,0,end-1);
        if(res!=-1) return true;
        res = binary_search(nums,target,end,n-1);
        return res!=-1;
    }
    int binary_search(vector<int>& nums,int target,int start,int end){
        int left=start,right=end;
        while(left<right){
            int mid=(left+right)/2;
            if(nums[mid]>=target) right=mid;
            else  left=mid+1;
        }
        return nums[right]==target?right:-1;
    }
};
posted @ 2021-04-07 12:14  Mrsdwang  阅读(30)  评论(0编辑  收藏  举报