问题1. 数组中没有重复的数字
/************************************************************************
*
* 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.
*
************************************************************************/
此题常规的解法为O(N),即遍历一遍数组,找到与target相同的索引,但是这种做法明显没有利用给的条件去做题。
二分的方法主要分两步:
- 找到旋转数组中最小值的索引,这一点很巧妙,可以用二分的方法去寻找这个最小值的索引,代码如下:
while (low<high) {
int mid=(low+high)>>1;
if (nums[mid]>nums[high]) low=mid+1;
else high=mid;
}
2.找到最小值点的索引后,我们就知道了他的旋转点再哪里,即
rot=low
旋转了rot个长度。
例如: 1 3 5 7 9
旋转成 5 7 9 1 3
,则旋转了3个长度。
那么在我们再一次用普通的二分查找mid
时,实际上我们是查找旋转数组中的realmid=(mid+rot)%length
因此二分搞定。
综上所述,完整AC代码如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int n=nums.size();
int low=0,high=n-1;
//find the smallest index
while (low<high) {
int mid=(low+high)>>1;
if (nums[mid]>nums[high]) low=mid+1;
else high=mid;
}
int rot=low;low=0,high=n-1;
//usualy binary search
while (low<=high) {
int mid=(low+high)>>1;
int realmid=(mid+rot)%n;
if (nums[realmid]==target) return realmid;
else if (nums[realmid]>target) high=mid-1;
else low=mid+1;
}
return -1;
}
};
问题2. 数组中有重复数字
/**********************************************************************************
*
* Follow up for "Search in Rotated Sorted Array":
* What if duplicates are allowed?
*
* Would this affect the run-time complexity? How and why?
*
* Write a function to determine if a given target is in the array.
*
**********************************************************************************/
class Solution {
public:
bool search(vector<int>& nums, int target) {
int left = 0, right = nums.size()-1, mid;
while(left<=right) {
mid = (left + right) >> 1;
if(nums[mid] == target) return true;
// the only difference from the first one, trickly case, just updat left and right
if( (nums[left] == nums[mid]) && (nums[right] == nums[mid]) ) {++left; --right;}
else if(nums[left] <= nums[mid]) {
if( (nums[left]<=target) && (nums[mid] > target) ) right = mid-1;
else left = mid + 1;
}
else {
if((nums[mid] < target) && (nums[right] >= target) ) left = mid+1;
else right = mid-1;
}
}
return false;
}
};