解法
此题难点在于我们不知道哪里是最大值,所以我们没办法用常规的二分法来解决。
思路:
当我们找mid的时候,我们要进行一个对比,对比mid和start对应的数字大小,。如果start对应的数字小,那么意味着,start到mid是上升单调;如果大,mid+1 到 end是上升单调。
然后我们需要判断,目标数在不在我们定的上面这两个范围里面,然后不断更新start和end,但是我们没法处理有重复的数字的情况。
class Solution {
public int search(int[] nums, int target) {
if(nums==null || nums.length==0) {
return -1;
}
//查找最小值的下标
int minIndex = findMin(nums);
//如果最小值下标为0,说明整个数组是有序的
if(minIndex==0) {
return binarySearch(nums,0,nums.length-1,target);
}
//最终结果在[0,min_index-1]中
if(nums[0]<=target) {
return binarySearch(nums,0,minIndex,target);
}
//最终结果在[min_index-1,length-1]中
return binarySearch(nums,minIndex,nums.length-1,target);
}
//正常的二分查找
private int binarySearch(int[] nums,int begin,int end,int target) {
while(begin<=end) {
int mid = begin+(end-begin)/2;
if(nums[mid]>target) {
end = mid-1;
}
else if(nums[mid]<target) {
begin = mid+1;
}
else {
return mid;
}
}
return -1;
}
//查找最小值的下标
private int findMin(int[] nums) {
int begin = 0;
int end = nums.length-1;
//如果第一个值比最后一个值小,说明整个数组是有序的
if(nums[begin]<=nums[end]) {
return begin;
}
while(begin<=end) {
int mid = begin+(end-begin)/2;
//前一个值比后一个值大,找到了旋转点
if(mid<nums.length-1 && nums[mid]>nums[mid+1]) {
return mid+1;
}
//中间点大于等于第一个元素,左半边是有序的,转去右边查找
if(nums[mid]>=nums[0]) {
begin = mid+1;
//左边是无序的,继续在左边查找
} else {
end = mid-1;
}
}
return 0;
}
}