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.
这是一个循环数组,在数组中找一个目标值,首先能够想到的就是O(n)的算法,把整个数组遍历一遍。
int length = nums.length;
for(int i = 0; i < length; i++){
<span style="white-space:pre"> </span>if(nums[i] == target){
<span style="white-space:pre"> </span>return i;
<span style="white-space:pre"> </span>}
}
return -1;
使用二分查找,可以把算法提升到log(n)。
循环递增数组的特点:数组中间的元素可以将数组划分为两个部分,一部分是严格递增的,另一部分是一个更小的循环递增数组。
1 2 3 4 5
5 1 2 3 4
4 5 1 2 3
3 4 5 1 2
2 3 4 5 1
因此可划分为两种情况,一种是,当nums[mid] >= nums[start]时,数组左半部分是严格递增的。
如果目标值在严格递增部分(target < nums[mid] && target >= nums[start]),则可以一次去掉右半部分,即 end = mid - 1,否则可以去掉左半部分。
另一种是当nums[mid] < nums[start]时,可以保证数组右半部分是严格递增的,同上使用二分搜索。
public class Solution {
public int search(int[] nums, int target) {
int start = 0;
int end = nums.length - 1;
while(start <= end){
int mid = (start + end) / 2;
if(nums[mid] == target){
return mid;
}
if(nums[mid] >= nums[start]){ //数组左边是有序的
if(target < nums[mid] && target >= nums[start]){
end = mid - 1;
}else{
start = mid + 1;
}
}else{ // 数组右边是有序的
if(target > nums[mid] && target <= nums[end] ){
start = mid + 1;
}else{
end = mid - 1;
}
}
}
return -1;
}
}
当数组有重复元素出现时,如{1,1,3,1},上述代码就不能很好的解决问题了,
原因是当nums[mid] == nums[start]时,已经不能判断出数组的递增区间,因此只需要将此种情况再单捡出来即可。
public class Solution {
public boolean search(int[] nums, int target) {
int start = 0;
int end = nums.length - 1;
while(start <= end){
int mid = (start + end) / 2;
if(nums[mid] == target){
return true;
}
if(nums[mid] > nums[start]){
if(target < nums[mid] && target >= nums[start]){
end = mid - 1;
}else{
start = mid + 1;
}
}else if(nums[mid] < nums[start]){
if(target > nums[mid] && target <= nums[end] ){
start = mid + 1;
}else{
end = mid - 1;
}
}else{ 当不能判断出递增区间时,start往下走一步即可
start++;
}
}
return false;
}
}