LeetCoder_____ 搜索旋转排序数组(33)

1. 思路

通过二分查找找到翻转点,然后再在两边进行二分查找。




2.代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l, r, point = -1, size = nums.size() - 1;
        l = 0, r = size;
        while(l <= r)
        {
            int mid = (l+r) >> 1;
            if(mid < size && nums[mid+1] < nums[mid])
            {
                point = mid;break;
            }
            if(nums[mid] >= nums[0]) l = mid + 1;
            else if(nums[mid] <= nums[size]) r = mid - 1;
        }
        int ret = 0;
        if(point != -1)
        {
            ret = search(nums, target, 0, point);
            if(ret >= 0) return ret;
            ret = search(nums, target, point + 1, size);
            if(ret >= 0) return ret;
        }
        else{
            ret = search(nums, target, 0, size);
            if(ret >= 0) return ret;
        }
        return -1;
    }

    int search(vector<int>& nums, int target, int left, int right)
    {
        while(left <= right)
        {
            int mid = (left+right) >> 1;
            if(nums[mid] < target) left = mid + 1;
            else if(nums[mid] > target) right = mid - 1;
            else return mid;
        }
        return -1;
    }
};




3. 大神思路

其实之前写二分查找一直都很玄学,因为二分查找思路很简单,框架很容易记。但是其中的细节就不是去理解。一般都是每次要写的时候,发现结果不对,看下bad-case也就能改对。
所以对二分查找理解不透彻的建议先看下这个文章: 二分查找细节理解

然后再来看下大神思路。

对于一般的二分查找来说,待搜索序列是单调的,所以我们能够根据单调性来将搜索区间向左压缩,或者向右压缩。
那么这个题目序列不是单调的,那么能够通过一次二分查找找到目标元素吗?
其实是可以的,因为二分查找的真正核心要求有序不是简单的比大小,而是在某个规则下有序:

对于任意一个元素,能够在O(1)的时间复杂度得到,目标元素在当前元素的左边还是右边。

那么对于这个题目,我们如何来分析呢:

首先,我们知道原数组可以分为前后两部分:

4 , 5, 61, 2, 3

这两部分都有规律:

  1. 两部分都是分别单调递增的。
  2. 后面部分比前面一部分每个数小。

那么根据这个规律的话,我们可以重新给这个序列定一个比较关系。

  1. 当都在同一个部分的时候,根据数字大小比较。
  2. 如果不在同一个部分的时候,数字大的反而小。

那么在新的比较关系下,那么这个序列就变成有序的了!




4. 大神代码

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

        while(left <= right)
        {
            int mid = (left + right) >> 1;
            if((target < nums[0]) ^ (nums[mid] < nums[0]) ^ (nums[mid] <= target))
            {
                left = mid + 1;
            }
            else
            {
                right = mid - 1;
            }
        }
        return right >= 0 && nums[right] == target ? right : -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值