什么是旋转数组?
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).
有一个转折点,0 ,需要考虑的特殊情况是 [1,2], [2,1]
进阶形式是这个数组中有重复的元素 尤其要注意 [1,1], [3,1,3], [4,4,4,4,4,4,1,2,3,4,4], [4,1,2,3,4,4,4,4,4,4,4] 这几种情况
第一类问题,在旋转数组中查找目标数 (无重复的元素)
思想:先求中间点的值A[mid]
①,如果A[mid] >= A[left], 说明从left到mid 是升序的,然后再判断target在不在这个区间,如果在,则让右边界right=mid-1,如果不在,则让左边界left=mid+1;
②,如果A[mid] < A[left],说明从mid到right都是升序,则同样道理判断target区间
代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
int search(int A[], int n, int target) {
int left = 0;
int right = n-1;
int mid ;
while(left<=right){
mid = (left+right)/2;
if(target == A[mid])
return mid;
if(A[mid]>=A[left]) //说明从left到mid是升序的,等号必须有,因为考虑输入为[3,1];
{
if((target>=A[left]) && (target<=A[mid]))
right = mid-1;
else
left = mid+1;
}
else //说明从mid到right是升序的;
{
if(target>=A[mid] && target<=A[right])
left = mid+1;
else
right = mid-1;
}
}
return -1;
}
};
int main()
{
int result;
Solution solution1;
int ia[3]={2,3,1};
//vector<int> vec(ia, ia+9);
int target;
cout<<"please input the target: ";
cin >>target;
result = solution1.search(ia, 3, target );
cout << "the result_index is " << result <<endl;
}
如果有重复元素,该怎么办?
干扰的因素是 A[left]==A[mid]==A[right]这种情况, 对于这种情况,去掉首尾继续下一次循环,代码如下:
class Solution {
public:
bool search(int A[], int n, int target) {
if(0 == n) return false;
int left = 0;
int right = n-1;
int mid ;
while(left<=right){
mid = (left+right)/2;
if(target == A[mid])
return true;
if(A[left] == A[mid] && A[mid] == A[right])
{
++left;
--right;
}
else if(A[mid]>=A[left]) //说明从left到mid升序或者相等的;
{
if((target>=A[left]) && (target<A[mid]))
right = mid-1;
else
left = mid+1;
}
else //说明从mid到right是升序或者相等的;
{
if(target>A[mid] && target<=A[right])
left = mid+1;
else
right = mid-1;
}
}
return false;
}
};
第二类问题:求转折点,也就是最小点 (无重复)
思路:
1,num[left] < num[right] 本身就是递增,直接返回num[left], num[left] == num[right] 也是循环结束的条件 返回num[left]
2,num[mid] >= num[left] 说明从left到mid是递增的,让left=mid+1,必须是大于等于,考虑输入[2,1]
3,num[mid] < num[left] 说明从mid到right是递增的,让right = mid 缩小范围
具体代码如下:
class Solution {
public:
int findMin(vector<int> &num) {
int left = 0;
int right = num.size() - 1;
int mid;
while(left <= right){
mid = (left + right) / 2;
if(num[left] <= num[right]) return num[left];
else if(num[mid] >= num[left]) left = mid + 1;
else right = mid;
}
}
};
class Solution {
public:
int findMin(vector<int> &num) {
int left = 0;
int right = num.size() - 1;
int mid;
while(num[left] >= num[right]){//这里必须是大于等于,考虑[3,1,3]情况出现,直接返回3
if(left >= right) return num[left];//这里必须是大于等于,考虑[1,1]情况出现
mid = (left + right)/2;
if(num[mid]==num[left] && num[mid]==num[right]){++left; --right;} //[4,5,6,7,1,2,3,4,4,4,4,4,4,4,4]以及[4,4,4,4,4,1,2,3,4]情况
else if(num[mid] >= num[left]) left = mid+1;
else right = mid;
}
return num[left];
}
};