33. 搜索旋转排序数组

2020-06-25  本文已影响0人  gykimo

https://leetcode-cn.com/problems/search-in-rotated-sorted-array/

我的方法一:先找到旋转点,然后再确定是在哪一段来二分查找

步骤:

  1. 判断是否有旋转,即判断第一位是否大于最后一位
  2. 当有旋转时,寻找旋转点
    2.1 begin和end分别表示数组的第一位和最后一位
    2.2 取中间点middle,判断middle是否比middle+1位数要大
    2.2.1 如果大,那么middle就是旋转点
    2.2.2 如果不大,当middle值比第一位小,那么end=middle-1
    2.2.3 如果不大,当middle值比第一位大,那么begin=middle+1
  3. 确定target在哪一段,即求的begin和end

初始值

  1. begin=0, end=nums.size()-1

边界条件

  1. begin要<=end
  2. nums的长度是否0或者1

复杂度

时间复杂度:O(logn),寻找旋转点和寻找target都采用二分查找
空间复杂度:O(1),只使用来begin、end、middle几个变量

代码

出现一个错误,就是当找到旋转点时一定要break;

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

        int begin = 0;
        int end = nums.size()-1;
        int middle = 0;
        //1. 判断是否有旋转,即判断第一位是否大于最后一位
        if(nums[begin] > nums[end]){
            while(begin <= end){
                //2.2 取中间点middle,判断middle是否比middle+1位数要大
                middle=(begin+end)>>1;
                if(nums[middle] > nums[middle+1]){
                    //2.2.1 如果大,那么middle就是旋转点
                    if(nums[middle] == target){
                        return middle;
                    }else if(nums[middle] < target){
                        return -1;
                    }else{
                        if(target >= nums[0] && target<= nums[middle]){
                            begin = 0;
                            end = middle;
                        }else if(target >= nums[middle+1] && target<= nums[nums.size()-1]){
                            begin = middle+1;
                            end = nums.size()-1;
                        }else{
                            return -1;
                        }
                    }
                    break;
                }else{
                    if(nums[middle] < nums[0]){
                        //2.2.2 如果不大,当middle值比第一位小,那么end=middle-1
                        end = middle-1;
                    }else{
                        //2.2.3 如果不大,当middle值比第一位大,那么begin=middle+1
                        begin = middle+1;
                    }
                }
            }
        }

        //cout<<"begin:"<<begin<<" end:"<<end<<endl;

        //3. 确定target在哪一段,即求的begin和end
        while(begin <= end){
            middle = (begin+end)>>1;
            if(nums[middle] == target){
                return middle;
            }else if(nums[middle] < target){
                begin = middle+1;
            }else{
                end = middle-1;
            }
        }
        return -1;
    }
};

其他人的更好解法

官方解法

https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/sou-suo-xuan-zhuan-pai-xu-shu-zu-by-leetcode-solut/
不需要寻找旋转点,直接在原数组上二分查找,思路更加清晰

步骤

  1. begin和end分别指向要搜索的一段区间
  2. 判断middle
    2.1 如果nums[begin] <= nums[middle],说[begin, middle]是有序的数组
    2.1.1 target==nums[begin], target是begin
    2.1.2 target==nums[middle], target是middle
    2.1.3 target>nums[begin] && nums[middle]> target,那么target肯定在[begin, middle-1]内
    2.1.4 否则[middle+1, end]内
    2.2 如果nums[begin] > nums[middle],说[middle,end]是有序的数组
    2.1.1 target==nums[end], target是end
    2.1.2 target==nums[middle], target是middle
    2.1.3 target>nums[middle] && nums[end]> target,那么target肯定在[middle+1, end]内
    2.1.4 否则[begin, middle-1]内

代码

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

        int begin = 0;
        int end = nums.size()-1;
        int middle = 0;
        
        while(begin <= end){
            middle = (begin+end)>>1;
            //cout << "begin:"<<begin<<" end:"<< end<<" mid:"<<middle<<endl;
            if(nums[begin] <= nums[middle]){
                if(target == nums[begin]){
                    //2.1.1 target==nums[begin], target是begin
                    return begin;
                }else if(target == nums[middle]){
                    //2.1.2 target==nums[middle], target是middle
                    return middle;
                }else if(target > nums[begin] && nums[middle]> target){
                    ////2.1.3 target>nums[begin]  && nums[middle]> target,那么target肯定在[begin, middle-1]内
                    end = middle-1;
                }else{
                    //2.1.4 否则[middle+1, end]内
                    begin = middle+1;
                }
            }else{
                if(target==nums[end]){
                    //2.1.1 target==nums[end], target是end
                    return end;
                }else if(target==nums[middle]){
                    //2.1.2 target==nums[middle], target是middle
                    return middle;
                }else if(target>nums[middle] && nums[end]> target){
                    //2.1.3 target>nums[middle]  && nums[end]> target,那么target肯定在[middle+1, end]内
                    begin = middle+1;
                }else {
                    //2.1.4 否则[begin, middle-1]内
                    end = middle-1;
                }
            }
        }

        return -1;
    }
};
上一篇下一篇

猜你喜欢

热点阅读