题目要求
给你旋转后的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
nums | target | return |
---|---|---|
[4,5,6,7,0,1,2] | 0 | 4 |
[4,5,6,7,0,1,2] | 3 | -1 |
[6,8,0,1,4,5] | 0 | 2 |
题解
二分法
最简单的二分法是:在有序数组中寻找目标值,mid为数组中间值,target 与 mid 比较大小,决定继续在哪一边寻找目标值,直到找到为止。
而旋转排序数组是局部有序的,不能简单直接的使用二分法。但观察数组可以发现,将旋转数组分成两组,无论怎么样分都会有一组是有序的。
所以我们可以让 target 与有序的这组比较大小,就可以直接判断目标值是在哪一组中,同样可以最终找到目标值
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
if (n == 0) return -1;
if (n == 1) return nums[0] == target ? 0 : -1;
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
//###########################
if (nums[0] <= nums[mid]) {
if (nums[l] <= target && target < nums[mid])
r = mid - 1;
else
l = mid + 1;
} else {
if (nums[mid] < target && target <= nums[r])
l = mid + 1;
else
r = mid - 1;
}
//###########################
}
return -1;
}
}
算法先简单判断了数组中没有值和只有一个值的情况,我们直接看核心【“ ### ”中的部分】,以上表中的第三个例子为例。
[6,8,0,1,4,5],target = 0
-
nums[mid] = 0 ,数组就分为【6,8,0】和【1,4,5】
-
if( nums[0] <= nums[mid] ){} else{}
是在判断 mid分开的两个数组,哪一个是有序的,然后进行目标值是否在此区域的判断。
在有序的这个区域,如果nums[mid]<target<=nums[r]
,l = mid + 1
在【1,4,5】中寻找目标值,否则r = mid-1
在【6,8,0】中寻找目标值。 -
【6,8,0】nums[mid] = 8
【6,8】 / 【0】
nums[l]<=target<nums[mid
不满足,l = mid + 1
,在【0】中寻找目标值。 -
【0】 nums[mid] = 0
nums[mid] == target
返回 mid。
来源:力扣(LeetCode)