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

来源:互联网 发布:怎样修改淘宝掌柜名字 编辑:程序博客网 时间:2024/05/24 03:22

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
原创粉丝点击