33. 搜索旋转排序数组

在这里插入图片描述
感觉写的很low很low,还干了90%的人,查找有序数组,虽然是有序的有点奇怪,但是还是一下想到二分
在这里插入图片描述
我的思路是先通过二分查找找到分割点,也就是最小值。那么分割点左边以及分割点右边都是有序的,根据target的值来判断去哪边寻找,再去哪边二分就行了。难的就是找最小值,剑指offer有一题一样的,我们在找最小值的过程中也加以判断,如果找到target的话直接返回就好了。如果mid>right,证明最小值一定在右边,left=mid+1,mid直接舍弃,因为太大了。如果mid小于right,证明在mid到right是单调递增的,所以在左边找,mid不能舍弃。如果相等,那就不一定了,左右都有可能,但是right一定不可能了,它一定>=最小值,反正mid还在,直接舍弃right,将right–缩小范围即可。最后结束循环时的left就是切分点。然后去两个区间二分即可。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.size() == 0) return -1;
        //被旋转过的,在分界线两侧还是有序的,用二分查找即可,logn,先通过二分查找找出切分点,切分点就是最小的那个数字
        //再在两个有序数组里找即可
        int left = 0, right = nums.size()-1;
        int qiefen;//切分点是
        while(left <= right){
            int mid = left + (right-left)/2;
            if(nums[mid] == target) return mid;
            if(nums[mid] > nums[right]){
                left = mid+1;//mid没用了,因为mid不是最小的
            }
            else if(nums[mid] < nums[right]){
                right = mid;
            }
            else{
                right--;
            }
        }   
        int left1 = 0, right1 = left-1,left2 = left, right2 = nums.size()-1;
        //两个有序数组
        /*if((target < nums[left1] && target > nums[right1])||
        target < nums[left2] || target > nums[right1]){
            return -1;
        }*/
        if(target > nums[right2]){//在左边查
            while(left1 <= right1){
                int mid = left1 + (right1-left1)/2;
                if(nums[mid]==target) return mid;
                else if(nums[mid] > target) right1 = mid-1;
                else left1 = mid+1;
            }
        }
        else{
            while(left2 <= right2){
                int mid = left2 + (right2-left2)/2;
                if(nums[mid] == target) return mid;
                else if(nums[mid] > target) right2 = mid-1;
                else left2 =mid+1;
            }
        }
        return -1;
    }
};

不是找某个特定数,就是返回left,找某个特定数一定能在里面找到,找不到就返回-1。先找到最小值。找某个特定数要left严格大于right才行,找区间left=right就可以退出了。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //有序数组的查找=二分查找
        //两边二分解决,第一遍找出最小值,也就是分割界限,然后去左右分别二分
        int left = 0, right = nums.size()-1;
        //循环什么时候结束?最后返回的是left的值,在搜边界的时候如果搜到target也行
        //不是找某个数,而是为了确定边界之类的,返回的left,而且是等于就可以退出了
        while(left < right){
            int mid = left + (right-left)/2;

            if(nums[mid] == target) return mid;

            //根据mid和high来查找边界,right如果大于mid,证明mid到right是有序的,在左边
            //如果right小于mid,证明无序,在右边
            //如果等于就让right--缩小范围
            if(nums[right] > nums[mid]){
                //mid比较小,不能直接忽视
                right = mid;
            }
            else if(nums[right] < nums[mid]){
                left = mid+1;
            }
            else{
                right--;
            }
        }
        //此时left就是最小值,它到最后是有序的,它前面的也是有序的
        int left1 = 0, right1 = left-1, left2 = left, right2 = nums.size()-1;
        //也可以提前判断是否存在,如果大于最大或者小于最小就是不存在
        //然后判断target在哪边
        if(target > nums[right2]){
            //找某个数的时候必须要严格大于才退出,等于不能退出!!
            while(left1 <= right1){
                int mid = left1 + (right1-left1)/2;
                if(nums[mid] == target){
                    return mid;
                }
                else if(nums[mid] < target){
                    //如果小于就去右边,mid不要了,因为mid不可能是target了
                    left1 = mid+1;
                }
                else{
                    right1 = mid-1;
                }
            }
        }
        else{
            while(left2 <= right2){
                int mid = left2 + (right2 - left2)/2;
                if(nums[mid] == target){
                    return mid;
                }
                else if(nums[mid] < target){
                    left2 = mid+1;
                }
                else{
                    right2 = mid-1;
                }
            }
        }
        return -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值