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.
這道題由於存在將有序數組進行了翻轉,二分查找方法就不能直接用了,必須將其變化纔可以正常使用,二分搜索的重點是判斷到底是應該向前找還是向後找。像這道題就存在這樣的問題,在全局low和high之中,數列是非有序的,而在某個局部low和high之間,數列很可能是有序的。所以首先需要一個判斷條件 是否A[low] < A[high],如果小於則是有序,如果大於則是無序。
其次,判斷找target的下一次二分位置是在前半段還是後半段。比如找6,不能只比較6和A[mid]的大小,因爲A[mid] = 7,而7的前半段和後半段都是小於7的數,這時候需要將target和A[high]比較以及A[mid]和A[high]比較。當 targe < A[mid]時,如果A[mid]>A[high](拐點在右邊)且target<=A[high](沒翻轉時target在拐點前半段)且A[low] > A[high](本段無序),就往後找,其他情況往前找。同理,target > A[mid]時,A[mid]<A[high](拐點在左邊)且target>A[high](沒翻轉時target在拐點後半段)且A[low]>A[high](本段無序),就往前找,其他情況往後找。
Source1
public class Solution {
public int search(int[] A, int target) {
return BinarySearch(0, A.length - 1, A, target);
}
public int BinarySearch(int low, int high, int[] A, int target){
while(low <= high){
int mid = low + ((high - low) >> 1);
if(A[mid] > target){
if(A[high] < A[low] && target <= A[high] && A[mid] > A[high]){
low = mid + 1;
}
else high = mid - 1;
}
else if(A[mid] < target){
if(A[high] < A[low] && target > A[high] && A[mid] < A[high]){
high = mid - 1;
}
else low = mid + 1;
}
else return mid;
}
return -1;
}
}
還有一種方法是用mid和low比,如果mid > low 證明左半部分有序,如果mid < low 證明右半部分有序,如果mid == low,此時的二分局部區間要麼只剩一個元素,要麼剩兩個元素,在if之前就先判斷了target是否與A[mid]相等,所以這裏的else語句只需要使low++。
Test
public static void main(String[] args){
int[] A = {4, 5, 6, 7, 0, 1, 2};
System.out.println(new Solution().search(A, 6));
}
Source2
public int search(int[] A, int target) {
int low = 0, high = A.length - 1;
while(low <= high){
int mid = low + ((high - low) >> 1);
if(target == A[mid]) return mid;
if(A[low] < A[mid]){ //左半部有序
if(A[low] <= target && target < A[mid]){
high = mid - 1;
}
else low = mid + 1;
}
else if(A[low] > A[mid]){ //右半有序
if(A[high] >= target && target > A[mid]){
low = mid + 1;
}
else high = mid - 1;
}
else low ++; // A[low] == A[mid] 只有兩種情況 要麼該局部區間一個值 要麼該局部區間兩個值
}
return -1;
}