LeetCode 面试题 10.03. 搜索旋转数组****(double,need triple)

基本思想:

一定要注意一下这道题,和“154. 寻找旋转排序数组中的最小值 II”思路类似,但是解决思路不同会有问题;

首先确定的是,肯定是用二分,但是一定要使其变为二段性;

何为二段性,就是指在二分的时候,一定要一半满足一个条件,另一半不满足,才能进行二分;

例如:
1,1,1,3,11,1,1,1,3一个可以二分,一个就不可以;

原因是第一个序列无法通过某个索引使其分割为1,1,1,3这两个序列;

154题给的题解是在遍历中直接忽略和mid相等的右边界;
在这里插入图片描述
而宫水三叶大佬则是:
在这里插入图片描述
这里注意一个重要问题:
看似两种方法都能解决,但是有本质区别;

官方题解只能选找到最小元素,但是无法寻找到拐点,也就是说,他找到的最小元素未必是真正的拐点;

例如:1,1,1,1,3,1;

按照官方题解的思路会将其转化为:
1,1,1,1,3;

此时,对比右边界,会找到第一个1;而其实真正拐点的1应该是3后面的1;

而按照宫水三叶的思路,也会将其转化为:
1,1,1,1,3;

但是由于对比的是左边界,寻找最大值后便可以找到第一位最小值;
因此会找到3,得到最小值应该是3后面的1;

同理,如果换个例子:
3,3,3,3,1,3;
转化为:
3,3,3,3,1;
则会找到最后一个3,可以找到最小值1;

因此,可以看到宫水三叶的思路是找到最大值,然后+1找到最小值即可;

所以此题可以转化为,找到拐点,分两边进行二分寻找;

具体代码:

class Solution {
public:
    int search(vector<int>& arr, int target) {
        int ret;
        int l=0,r=arr.size()-1;
        while(r>=0&&arr[0]==arr[r]){
            r--;
        }
        //先找到最小元素边界;
        while(l<r){
            int mid=(l+r+1)>>1;
            if(arr[0]<=arr[mid]){
                l=mid;
            }else{
                r=mid-1;
            }
        }
        //分为两半进行遍历;
        if(target>=arr[0]){
            ret=search(0,l, target, arr);
        }else{
            ret=search(l+1, arr.size()-1, target, arr);
        }
        if(target==arr[ret])
            return ret;
        return -1;
    }
    int search(int left,int right,int target,vector<int>& arr){
        int l=left,r=right;
        while(l<r){
            int mid=l+(r-l)/2;
            if(arr[mid]>=target){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        return l;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值