33. 搜索旋转排序数组

33. 搜索旋转排序数组

题目描述

升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。

请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1

示例1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例3:

输入:nums = [1], target = 0
输出:-1

提示:

  • 1 ≤ n u m s . l e n g t h ≤ 5000 1 \le nums.length \le 5000 1nums.length5000
  • − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10^4 \le nums[i] \le 10^4 104nums[i]104
  • nums 中的每个值都 独一无二
  • nums 肯定会在某个点上旋转
  • − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10^4 \le target \le 10^4 104target104

题解:

此题肯定是二分,但是怎么二分大有学问。

参考 在有序旋转数组中找到最小值 ,两题基本一样,核心思想没变。

欢迎尝试进阶版(带重复值):在有序旋转数组中找到一个数

法一:

两次二分,先确认 target 在哪个区间(找到分界点),然后再该区间上进行普通的二分即可。

也就是 把复杂问题分解成简单的子问题

法一代码:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        int l = 0, r = n - 1, m;
        if ( nums[n - 1] < nums[0] ) {
            while ( l < r ) {
                m = ( l + r ) >> 1;
                if ( nums[m] >= nums[0] ) l = m + 1;
                else r = m;
            }
            if ( target <= nums[n - 1] ) r = n - 1;
            else l = 0, --r;
        }
        while ( l < r ) {
            m = (l + r) >> 1;
            if ( nums[m] == target ) return m;
            if ( nums[m] > target ) r = m;
            else l = m + 1;
        }
        return nums[r] == target ? r : -1;
    }
};
/*
时间:4ms,击败:92.60%
内存:10.7MB,击败:98.53%
*/
法二:

一次二分,在二分中添加一些判断,确认 target 在哪个区间:

  • nums[mid] >= nums[0] ,说明 mid 在左边区间:

    1. target >= nums[l] && target <= nums[mid] ,说明此时需要在区间 [l,mid] 上查找,即 r = mid
    2. target < nums[l] || target > nums[mid] ,说明 targetmid 右边,即 l = mid + 1
  • nums[mid] < nums[0] ,说明此时 mid 在右边区间:

    1. target <= nums[mid] || target > nums[n - 1] ,说明 targetmid 左边, 即 r = mid

    2. 否则的话,说明 targetmid 右边,即 l = mid + 1

法二代码:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        int l = 0, r = n - 1, m;
        while ( l < r ) {
            m = ( l + r ) >> 1;
            if ( nums[m] == target ) return m;
            if ( nums[m] >= nums[0] ) {
                if ( target >= nums[0] && target <= nums[m] ) r = m;
                else l = m + 1;
            } else {
                if ( target <= nums[m] || target > nums[n - 1] ) r = m;
                else l = m + 1;
            }
        }
        return nums[r] == target ? r : -1;
    }
};
/*
时间:4ms,击败:92.60%
内存:10.8MB,击败:97.18%
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值