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).
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
binary search 变形题,稍微比基本题绕了点弯。在用二分法把数组分为两段后,至少有一段还是单调递增的,如果target在这段递增区间,就可以继续利用二分法查找;如果在另一段,那就回到了本题的初始状态,再分两段找单调区间。最后剩下相邻的两个数[low, high] or [high, low]两种可能
写的时候要注意各种情况的边界条件,line 12 判断条件没考虑nums[mid] == nums[left]的情况,导致在[high, low]的情况下无法处理,找不到target
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > nums[left]) {
if (nums[mid] > target && target >= nums[left]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
}
[3,1]
1
Output:
-1
Expected:
1
改正后可以得到正确答案
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] >= nums[left]) {
if (nums[mid] > target && target >= nums[left]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
}
time:O(lon(n))
space: O(1)
另外参考这篇文章,还有其他两种解法。
public int search(int[] nums, int target) {
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int num = nums[mid];
//nums [ mid ] 和 target 在同一段
if ((nums[mid] < nums[0]) == (target < nums[0])) {
num = nums[mid];
//nums [ mid ] 和 target 不在同一段,同时还要考虑下变成 -inf 还是 inf。
} else {
num = target < nums[0] ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
if (num < target)
lo = mid + 1;
else if (num > target)
hi = mid - 1;
else
return mid;
}
return -1;
}
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] > nums[end]) {
start = mid + 1 ;
} else {
end = mid;
}
}
int bias = start;*/
//找出最大值的数组下标
while (start < end) {
int mid = Math.round(((float)start + end) / 2);
if (nums[mid] < nums[start]) {
end = mid - 1;
} else {
start = mid;
}
}
int n = nums.length;
int bias = (start + n) - (n - 1); //得到偏移
start = 0;
end = nums.length - 1;
while (start <= end) {
int mid = (start + end) / 2;//中间的位置
int mid_change = (mid + bias) % nums.length;//中间的位置对应的数组下标
int value = nums[mid_change];//中间位置的值
if (target == value) {
return mid_change;
}
if (target < value) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return -1;
}