Search in Rotated Sorted Array (M)
题目
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 = 0
Output: 4
题意
将一递增数列的随机后半部分与前半部分换位,得到新数组,在新数组中查找目标值。
思路
比较简单的做法是先用一个二分找到两个递增序列的边界,再用一个二分在对应的递增序列里查找目标值。
也可以只用一个二分完成操作:求出mid,先考虑mid落在右递增区间的情况,如果target也落在右递增区间且比nums[mid]大,说明只需要继续向右查找,令 left = mid + 1 即可,不然只要向左查找,令 right = mid - 1;同理,对于mid落在左递增区间的情况进行处理。
代码实现
Java
不求边界
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
}
// 通过与第一个值相比较来判断mid落在左区间还是右区间
if (nums[mid] < nums[left]) {
if (target <= nums[right] && target > nums[mid]) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (target >= nums[left] && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return -1;
}
}
先求边界
class Solution {
public int search(int[] nums, int target) {
if (nums.length == 0) {
return -1;
}
int left = 0;
int right = nums.length - 1;
int split = nums.length - 1; // 默认不存在边界
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[mid] >= nums[left]) {
if (mid + 1 < nums.length && nums[mid + 1] < nums[mid]) {
split = mid;
break;
} else {
left = mid + 1;
}
} else {
if (mid - 1 >= 0 && nums[mid - 1] > nums[mid]) {
split = mid - 1;
break;
} else {
right = mid - 1;
}
}
}
// 选择一个递增区间进行二分查找
if (target >= nums[0]) {
return binarySearch(nums, 0, split, target);
} else {
return binarySearch(nums, split + 1, nums.length - 1, target);
}
}
private int binarySearch(int[] nums, int left, int right, int target) {
while (left <= right) {
int mid = (left + right) / 2;
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
}
JavaScript
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function (nums, target) {
let left = 0, right = nums.length - 1
while (left <= right) {
let mid = Math.trunc((right - left) / 2) + left
if (nums[mid] === target) {
return mid
}
if (target < nums[0] && nums[mid] >= nums[0]) {
left = mid + 1
} else if (target >= nums[0] && nums[mid] < nums[0]) {
right = mid - 1
} else if (nums[mid] < target) {
left = mid + 1
} else {
right = mid - 1
}
}
return -1
}