题目:https://leetcode.com/problems/search-in-rotated-sorted-array/
思路:
有序数列里头找元素,第一想到的肯定是二分法,但是现在数组的一部分被旋转过了,这怎么改进呢?假定输入是[4 5 6 7 0 1 2],如果仍用二分法,那么第一次搜索时,左中右的元素分别是a[left] = 4; a[mid]=7; a[right]=2
从题设可以知道,问题的关键是,被拆分的两个部分里,肯定是一半有序一半无序的(因为旋转点,即a[i+1] > a[i]的i点)肯定只能在两部分的其一里头,而对于有序的那一半,我们可以通过首末元素判断target是否在其中,于是有了下面的规则:
- 观察被二分出来的左半段(当然右半段也可以),根据a[left],a[mid]的值判断这半段是否有序
- 如果有序,根据头尾元素判断target是否在里头,如果在,那就搜索左半端,否则只能在无序的右半段里找了
- 如果无序,那右半段肯定是有序的,去判断target是否在右半段里头:如果在,则搜索右半段,否则还是老老实实把左半端再二分了找吧..
想比普通的二分,这个方法多了几个判断的步骤,但整体的时间复杂度还是O(logN)
代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid;
while(left <= right){
mid = (left + right) / 2;
if(target == nums[mid])
return mid;
if(nums[left] <= nums[mid]){
//The left part is in order, check if target is inside
if(nums[left] <= target && nums[mid] >= target){
//Yep, move to the left part
right = mid - 1;
} else {
//Nope, move to the right part
left = mid + 1;
}
} else {
//The left part is not in order, but the right one should be, check if target is in the right wing
if(nums[mid] <= target && nums[right] >= target){
//Yep, move to the right wing
left = mid + 1;
} else {
//Nope, try in the left wing
right = mid - 1;
}
}
}
return -1;
}
};