Suppose an array sorted in ascending order 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.
Your algorithm's runtime complexity must be in the order of O(log n).
假设某个递增排序的数组在某个点进行了旋转,比如[0,1,2,4,5,6,7] 可能变成了[4,5,6,7,0,1,2]
给你一个目标值进行查找。如果没找到,返回-1.假设没有重复的值。 你的算法复杂度应该为O(log n).
解题思路:在没有旋转的时候,排序数组查找应该使用二分法。现在被旋转了一次,要求还是O(log n),那么就应该还是二分法,只不过每次查找时多增加了一些判断方法而已。代码和注解如下所示:
public int search(int[] nums, int target) {
int n = nums.length;
if(n == 0){
return -1;
}
int low = 0;
int high = n-1;
int first_value = nums[0];
// 判断目标值,是否大于数组的第一个值
boolean target_big = target >= first_value;
while(low <= high){
int middle = (low + high)/2;
int middle_value = nums[middle];
if(target == middle_value){
return middle;
}
// 判断此次中间值,是否大于数组的第一个值
boolean middle_big = middle_value >= first_value;
if(middle_big == target_big){
if(middle_value < target){
low = middle + 1;
}else{
high = middle -1;
}
}else{
if(middle_big){
low = middle + 1;
}else{
high = middle -1;
}
}
}
return -1;
}
可以分成四种情况讨论: 初始情况 max_order + min_order: 也就是大的递增序列 + 小的递增序列
-
- 目标值 target_big = true,表示目标值在左边较大的递增序列中。本次循环中间值 middle_big = true,表示中间值大于数组第一个值,这表示此次循环中,左边还是单调递增序列。
//表示了左边还是单调递增序列
if(middle_big && target_big){
if(middle_value < target){
//如果中间值小于目标值,则目标值如果存在的话,则在右半边中
low = middle + 1;
}else{
// 中间值大于目标值,则在左半边中
high = middle -1;
}
}
-
- 目标值 target_big = false,表示目标值如果存在的话,在初始数组的右半边较小的递增序列中。middle_big = false,表示此次循环中间值小于数组的第一个值,所以 左边-中间 和 中间-右边 还是初始队列一样的排序。
// 左半边 和 右半边都是两个 递增--递增 序列
if( !middle_big && !target_big){
if(middle_value < target){
//中间值小于目标值
low = middle +1;
}else{
high = middle - 1;
}
}
总结这两种情况,就是当middle_big == target_big 时,如果中间值小于目标值,就再次在右半边查找,否则在左半边查找。
if(middle_big && target_big){
if(middle_value < target){
low = middle + 1;
}else{
high = middle -1;
}
}
-
- 当 middle_big = true, target_big = false时,表示此次循环左边是单调递增序列,但是目标值在右边较小的递增序列min_order中,所以继续在右边查找:
if(middle_big){
low = middle + 1;
}
-
- 当middle_big = false, target_big = true时,表示此次循环右边是单调递增序列,但是因为目标值在左边较大的初始递增序列中,所以继续在左边查找:
high = middle - 1;
所以最后代码如第一个代码框所示。