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.
两次二分,一次找到rotate的位置,一次找target。
就是说,排序数组可能是右移了一定位数。让你在这个数组中找一个target值。当然用线性查找就没意义了。
想这个解法需要头脑比较清晰。记得原来高中做题,老师最常说的一句话是啥?”要揣摩出题人意图啊“。。。这道题也是这样的。如果是在一个有序数组里面找一个值,那么一般都是用binarySearch。现在数组变了,(当然,还保持一些其他特点,我们下面说),能不能用binarySearch呢,或者我们改一下binarySearch呢?
如果用binarySearch,我们在通过Low和High序号得到Mid以后,应该如何剔除一半的数据呢?
下面是rotate后的一个有序数组的图。四边形的斜边表示数组中数值的大小。
在这种情况下数组分了两部分,分别都是有序(递增)的。
当我们计算了Mid以后,有两种可能,分别用Mid1和Mid2表示。
1. 如果A[Low] < A[Mid],说明Mid落在区间1中,即图中Mid1的位置。那么,如果target小于A[Mid1],那么继续在Low和Mid1中间搜索;否则,在Mid1和High中间搜索;
2. 如果A[Low] >= A[Mid],说明Mid落在区间2中,即图中Mid2的位置。同理,如果target小于A[Mid2],那么继续在Low和Mid2中间搜索;否则,在Mid2和High中间搜索。
这样,平均地,我们每次剔除一半数据,时间复杂度是O(logn)。
代码如下:
1 public class Solution { 2 public int search(int[] A, int target) { 3 // Note: The Solution object is instantiated only once and is reused by each test case. 4 //first divide find that point rotated, second one find that value 5 assert(A!=null); 6 int start = 0, 7 end = A.length-1; 8 while(start<=end){ 9 int mid = (start+end)/2; 10 if(A[mid]==target) 11 return mid; 12 if(A[mid]>target && (A[end]>A[mid] || A[end]<target) 13 || A[mid]<target && A[end]>A[mid] && A[end]<target){ 14 end=mid-1; 15 }else{ 16 start=mid+1; 17 } 18 } 19 return -1; 20 } 21 }
第二遍:
分类的方式很特别:
这里是按某一部分是不是sorted 来分的。
如果start < mid, 说明左边是sorted,那么 若 target 落在这个区间内 则 end = mid - 1;
如果不是,说明右边是sorted,那么若target 落在这个区间内 则 start = mid + 1;
1 public class Solution { 2 public int search(int[] A, int target) { 3 // Note: The Solution object is instantiated only once and is reused by each test case. 4 //first divide find that point rotated, second one find that value 5 int end = A.length - 1; 6 int start = 0; 7 while(start <= end){ 8 int mid = (end + start) / 2; 9 if(target == A[mid]) return mid; 10 if(A[start] <= A[mid]){//left half is sorted 11 if(A[start] <= target && target < A[mid]) end = mid - 1; 12 else start = mid + 1; 13 } 14 else{ 15 if(A[mid] < target && target <= A[end]) start = mid + 1; 16 else end = mid - 1; 17 } 18 } 19 return -1; 20 } 21 }