题目:
假设有个有序数组在某个位置旋转,得到新的数组,即为旋转有序数组。如:(i.e., 0 1 2 4 5 6 7
might become 4 5 6 7 0 1 2
).
现给定一个这样的数组,在数组中查找某个数。如果找到,返回下标,否则返回-1;
思路:
思路1:
考虑一个旋转有序数组的特点:前面部分是递增的,后面部分也是递增的,即先后两部分都为递增有序数组,因此可以用二分查找来做。
假设数组为A,下标从left到right,查找的数字为target,那么mid=(left+((right-left)>>1))
如果A[mid]==target,则return mid;
如果A[mid]>target或者A[mid]<target怎么办呢?以mid为界,左右两边不一定是有序的数组。此时我们先不比较A[mid]和target的大小。
以mid为界,左右两边必定有一边为递增的有序数组,那么这就是我们要找的区间。
如果A[mid]>A[left],那么mid的左边部分为递增有序数组,如果target>=A[left] && target<A[mid],那么right=mid-1;否则,left=mid+1;
如果A[mid]<A[left],那么mid的右边部分为递增有序数组,如果target>A[mid] && target<=A[right],那么left=mid+1;否则,right=mid-1;
思路2:
当然,我们也可以从正常的思路去想,分别从A[mid]==target,A[mid]>target,A[mid]<target三部分去考虑边界条件。(详见代码)
代码:
#include<iostream> using namespace std; int RotateArraySearch_1(int *A,int len,int target){ int left=0; int right=len-1; while(left<=right){ int mid=left+((right-left)>>1); if(A[mid]==target) return mid; if(A[mid]>A[left]){ if(target>=A[left] && target<A[mid]) right=mid-1; else left=mid+1; } else{ if(target>A[mid] && target<=A[right]) left=mid+1; else right=mid-1; } } return -1; } int RotateArraySearch_2(int *A,int len,int target){ int left=0; int right=len-1; while(left<=right){ int mid=left+((right-left)>>1); if(A[mid]==target) return mid; else if(target>A[mid]){ if(A[mid]>A[left] || target<=A[right]) left=mid+1; else right=mid-1; } else{ if(A[mid]<A[right] || target>=A[left]) right=mid-1; else left=mid+1; } } return -1; } int main(){ int A[]={2,3,4,5,1}; int B[]={5,1,2,3,4}; int n=sizeof(A)/sizeof(A[0]); cout<< RotateArraySearch_1(A,n,5) <<endl; cout<< RotateArraySearch_1(A,n,3) <<endl; cout<< RotateArraySearch_2(B,n,1) <<endl; cout<< RotateArraySearch_2(B,n,4) <<endl; return 0; }