LeetCode:33. Search in Rotated Sorted Array

之前写过一次这个题目,但是写的有点乱,这次重新写一遍
在这里插入图片描述
推荐记住两种方法。第一种方法容易理解,但是不好用到有重复值的情况下,而且代码比较长。第二种技巧性比较强,稍加改动可以用到有重复值的情况下。
方法一:找到最大值的位置。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int maxIdx = findMaxIndex(nums);
        if (maxIdx == -1)
            return -1;
        int retIdx = binarySearch(nums, 0, maxIdx, target);
        if (retIdx != -1)
            return retIdx;
        retIdx = binarySearch(nums, maxIdx+1, nums.size()-1, target);
        return retIdx;
    }
private:
    int findMaxIndex(vector<int>& nums) {
        int sz = nums.size();
        if (sz == 0)
            return -1;
        if (sz == 1)
            return 0;
        if (nums[sz-1] > nums[0])
            return sz-1;
        if (nums[0] > nums[1])
            return 0;
        int lo = 1, hi = sz-2;
        int mid;
        while (lo <= hi) {
            mid = lo + (hi - lo) / 2;
            if (nums[mid] > nums[mid-1] && nums[mid] > nums[mid+1])
                return mid;
            if (nums[mid] > nums[0])
                lo = mid + 1;
            else 
                hi = mid - 1;
        }
        return lo;//应该走不到这一步
    }
    
    int binarySearch(vector<int>& nums, int lo, int hi, int target) {
        if (lo > hi)
            return -1;
        int mid;
        while (lo <= hi) {
            mid = lo + (hi - lo) / 2;
            if (nums[mid] == target)
                return mid;
            else if (nums[mid] > target)
                hi = mid - 1;
            else
                lo = mid + 1;
        }
        return -1;
    }
};

说它不能用到有重复值的情况下是因为:在找最大值的函数中,不能根据和nums[0]比较还知道最大值在左边还是右边。

方法二:
方法大意就是:给这样的旋转的有序数组切一刀,至少会有一半是有序的。那么有序的那一半的数值范围就可以知道,而无序的数值范围还不知道。所以如果target落在有序那一边,就直接在其中二分查找就行了。否则就只能在无序的那一半中找了。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int lo = 0, hi = nums.size()-1, mid;
        while (lo <= hi) {//最需要注意的是:lo-hi范围内的数组既可能是无序的,也可能是有序的。
            mid = lo + (hi - lo) / 2;
            if (nums[mid] == target)
                return mid;
            //如果是有序的,那么流程会走到这个if内结束,不会到下个else中的。因为nums[mid]肯定大于等于nums[lo]
            if (nums[mid] >= nums[lo]) {//如果左边有序
                if (target >= nums[lo] && target < nums[mid])//并且target在左边范围内,就在左边找
                    hi = mid - 1;
                else//否则,到右边找
                    lo = mid + 1;
            } else {//否则右边有序
                if (target > nums[mid] && target <= nums[hi])
                    lo = mid + 1;
                else
                    hi = mid - 1;
            }
        }
        return -1;
    }
};

有点难以理解的是:这个二分查找的循环里,范围内的数组既可能是有序的,也可能是无序的。需要注意的是,它能正确的处理这两种情况。

posted @ 2019-08-26 10:38  于老师的父亲王老爷子  阅读(16)  评论(0编辑  收藏  举报