[LeetCode]33 旋转后的有序数组中的搜索

Search in Rotated Sorted Array(旋转后的有序数组中的搜索)

【难度:hard or Easy】
Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.
假设一有序数组在你不知道的情况下绕某一点旋转,如[0,1,2,4,5,6,7]旋转后变为了[4,5,6,7,0,1,2]。给定一个目标值,如果在旋转后的数组中能够找到,则返回其下标,否则返回-1。


解题思路

一看到有序数组,大家很自然就想到使用二分查找的方法,快速有效。但是旋转后的数组顺序已经改变了,常规的二分查找不能奏效。通过观察,我们知道原来全体有序的数组在旋转后变为了两个部分内部有序,因此如果对二分查找的方法进行一些调整,还是可以实现查找功能的。
我来举个例子:
假如有这样旋转后的数组为
[12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

  • 如果目标值为14, 那么我们可以把数组理解为下面的样子:
    [12, 13, 14, 15, 16, 17, 18, 19, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX]

  • 如果目标值为 7, 则将数组理解为下面的样子:
    [INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

那么对于上面的情况,使用常规的二分查找是可以实现的。
但是我们在数组情况未知下,不是真的这样去修改数组内容,而是在运行时动态地更改我们看到的数据的样子。
如何更改?关键在于这几行代码:

int mid = (low+high)/2;
int num = (nums[mid] < nums[0]) == (target < nums[0]) ? nums[mid] : target < nums[0] ? INT_MIN : INT_MAX;
if (num < target)
    low = mid+1;
else if (num > target)
    high = mid;
else
    return mid;

这段代码的作用是,判断中点的值nums[mid]与目标值target是否都在nums[0]的同一边(同true或同false):
1)是,则取num = nums[mid],根据num和target的大小关系来判断target可能位于的区间;
2)否,则进一步判断target < nums[0]是否成立:
如果成立,则说明nums[mid] >= nums[0],区间[0,mid]是升序区间,target不可能存在这个区间内,将num设置为INT_MIN,从而在下一个判断语句中将下边界变为mid+1;
如果不成立,则说明target >= nums[0] && nums[mid] < nums[0]为true,那么区间[mid,size-1]内的所有数小于target,将num设置为INT_MAX,从而在下一个判断语句中将上边界变为mid(而不是mid-1,因为mid-1还未与target比对)


c++代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if (nums.empty())
            return -1;

        int low = 0;
        int high = nums.size();
        while (low < high) {
            int mid = (low+high)/2;
            int num = (nums[mid] < nums[0]) == (target < nums[0]) ? nums[mid] : target < nums[0] ? INT_MIN : INT_MAX;
            if (num < target)
                low = mid+1;
            else if (num > target)
                high = mid;
            else
                return mid;
        }
        return -1;

    }

};

但是,除了二分查找的方法外,有个简单又粗暴的解法——遍历查找!
可能这道题的样例组数不够大,我使用上面的方法和遍历查找的方法耗时都在4ms,但是遍历查找无疑是最最直接,代码量还小。


遍历c++代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if (nums.empty())
            return -1;
        int high = nums.size();
        for (int i = 0; i < high; i++)
            if (nums[i] == target)
                return i;
        return -1;

    }

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值