33. Search in Rotated Sorted Array
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.
分析
题中给出的序列是由两个已经排序的序列合并而成的,并且后面的有序序列的所有数都是比第一个序列的首元素小,这里有两种思路:
找到这个pivot所在的位置,然后用target和这个pivot所在元素比较,找出target在前半段还是后半段范围内,然后在这个找到的范围内用二分法查找
直接使用二分查找法,只是这里的二分法稍微复杂了点。
如果nums[first] <= nums[mid]
,那么first
到mid
之间是有序的,这个时候判断target
是否在first...mid
之间,在的话last=mid
,如果不在,那肯定在mid+1...last
之间,first=mid+1
;
否则nums[first] > nums[mid]
,那么pivot在first…mid之间,即mid…last之间是有序的,这个时候判断target
是否在mid...last
之间,在的话first=mid+1
,如果不在,那肯定在first...mid
之间,last=mid
源码
方法1:先找pivot,然后用二分法
int binarySearch(vector<int>& nums, int start, int end, int target) {
// 递归二分法
// if((end - start) == 1 || end == start) {
// if(nums[start] == target) return start;
// else if(nums[end] == target) return end;
// else return -1;
// }
// int middle = (end + start) / 2;
// if(nums[middle] == target) return middle;
// else if(nums[middle] < target) start = middle;
// else end = middle;
// return binarySearch(nums,start,end,target);
//循环二分法
int middle, low = start, high = end;
int ret = -1;
while(low <= high) {
middle = (low + high) / 2;
if(nums[middle] == target) {
ret = middle;
break;
} else if(nums[middle] < target) {
low = middle + 1;
} else {
high = middle - 1;
}
}
return ret;
}
//寻找pivot
int indexOfPivot(vector<int>& nums) {
int index = -1;
if(nums.size() < 2) return index;
for(int i = 1; i < nums.size(); i++) {
if(nums[i] < nums[i-1]) {//当前数比前一数小,因为没有重复数,所以可以直接判断
index = i;
break;
}
}
return index;
}
int search(vector<int>& nums, int target) {
if(nums.size() == 0) return -1;
int pivot = indexOfPivot(nums);
if(pivot == -1) return binarySearch(nums, 0, nums.size() - 1, target);//没有pivot,直接二分法
else if(nums[pivot] <= target && target <= nums[nums.size()-1]) return binarySearch(nums,pivot,nums.size() - 1, target);
else if(nums[pivot - 1] >= target) return binarySearch(nums,0,pivot - 1, target);
else return -1;
}
方法二:直接二分法
int search(const vector<int>& nums, int target) {
int first = 0, last = nums.size();
while (first != last) {
const int mid = first + (last - first) / 2;
if (nums[mid] == target)
return mid;
if (nums[first] <= nums[mid]) { // 因为序列没有重复元素,这里等号不需要也可以; first...mid之间都是顺序的
if (nums[first] <= target && target < nums[mid])
last = mid;
else
first = mid + 1;
} else { // nums[first] > nums[mid] 说明序列扭转点发生在first...mid之间,但是mid之后的数是顺序的
if (nums[mid] < target && target <= nums[last-1])
first = mid + 1;
else
last = mid;
}
}
return -1;
}