题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1。
示例:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
解题思路
在一个经过排序的数组中寻找一个目标值,这是二分法的典型场景。在这题中,虽然数组排序后经过了旋转,看似更复杂了,好像重新变成了乱序,没法再用二分法。但事实上仔细观察会发现,选中数组中的任何一个元素,它的左右两边的子数组中一定有一个是有序的,在有序数组中我们可以使用二分查找,如果目标值在无序的那一部分,我们也可以通过选取新的元素来使得它变成有序和无序的两部分,对应到二分查找,这个要选取的元素就是中间元素。具体步骤如下
(1)选取中间元素,和目标值进行比较
(2)如果和目标值相等,返回中间的index
(3)如果中间元素的左边是有序的,就看目标值是否在左边,如果在左边,可以正常使用二分算法,如果不在左边,就去右边找
(4)如果中间元素的右边是有序的,就看目标值是否在右边,如果在,可以正常使用二分法,如果不在,就去左边找
(5)重复(1)(2)(3)(4)直到找到目标值或者无法再选取到中间值
代码如下:
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0)
return -1;
// binary search
int low = 0, high = nums.length - 1;
int n = nums.length;
while (low <= high) {
int mid = low + (high - low) / 2;
if (target == nums[mid]) {
return mid;
}
// 注意这边的if一定要有等于号,否则会出错
if (nums[low] <= nums[mid]) {
// 左边有序
if (target >= nums[low] && target < nums[mid]) {
// 在左边
high = mid - 1;
}
else {
low = mid + 1;
}
}
else {
// 右边有序
if (target <= nums[high] && target > nums[mid]) {
low = mid + 1;
}
else {
high = mid - 1;
}
}
}
return -1;
}
}