LeetCode:33. Search in Rotated Sorted Array
之前写过一次这个题目,但是写的有点乱,这次重新写一遍
推荐记住两种方法。第一种方法容易理解,但是不好用到有重复值的情况下,而且代码比较长。第二种技巧性比较强,稍加改动可以用到有重复值的情况下。
方法一:找到最大值的位置。
class Solution {
public:
int search(vector<int>& nums, int target) {
int maxIdx = findMaxIndex(nums);
if (maxIdx == -1)
return -1;
int retIdx = binarySearch(nums, 0, maxIdx, target);
if (retIdx != -1)
return retIdx;
retIdx = binarySearch(nums, maxIdx+1, nums.size()-1, target);
return retIdx;
}
private:
int findMaxIndex(vector<int>& nums) {
int sz = nums.size();
if (sz == 0)
return -1;
if (sz == 1)
return 0;
if (nums[sz-1] > nums[0])
return sz-1;
if (nums[0] > nums[1])
return 0;
int lo = 1, hi = sz-2;
int mid;
while (lo <= hi) {
mid = lo + (hi - lo) / 2;
if (nums[mid] > nums[mid-1] && nums[mid] > nums[mid+1])
return mid;
if (nums[mid] > nums[0])
lo = mid + 1;
else
hi = mid - 1;
}
return lo;//应该走不到这一步
}
int binarySearch(vector<int>& nums, int lo, int hi, int target) {
if (lo > hi)
return -1;
int mid;
while (lo <= hi) {
mid = lo + (hi - lo) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] > target)
hi = mid - 1;
else
lo = mid + 1;
}
return -1;
}
};
说它不能用到有重复值的情况下是因为:在找最大值的函数中,不能根据和nums[0]比较还知道最大值在左边还是右边。
方法二:
方法大意就是:给这样的旋转的有序数组切一刀,至少会有一半是有序的。那么有序的那一半的数值范围就可以知道,而无序的数值范围还不知道。所以如果target落在有序那一边,就直接在其中二分查找就行了。否则就只能在无序的那一半中找了。
class Solution {
public:
int search(vector<int>& nums, int target) {
int lo = 0, hi = nums.size()-1, mid;
while (lo <= hi) {//最需要注意的是:lo-hi范围内的数组既可能是无序的,也可能是有序的。
mid = lo + (hi - lo) / 2;
if (nums[mid] == target)
return mid;
//如果是有序的,那么流程会走到这个if内结束,不会到下个else中的。因为nums[mid]肯定大于等于nums[lo]
if (nums[mid] >= nums[lo]) {//如果左边有序
if (target >= nums[lo] && target < nums[mid])//并且target在左边范围内,就在左边找
hi = mid - 1;
else//否则,到右边找
lo = mid + 1;
} else {//否则右边有序
if (target > nums[mid] && target <= nums[hi])
lo = mid + 1;
else
hi = mid - 1;
}
}
return -1;
}
};
有点难以理解的是:这个二分查找的循环里,范围内的数组既可能是有序的,也可能是无序的。需要注意的是,它能正确的处理这两种情况。