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;
}