- 难度:
中等
- 本题涉及算法:
二分查找
- 思路:
旋转数组
- 类似题型:
题目 33. 搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
解题思路
- 被旋转的值肯定小于 nums[0]
解题思路一 直接对旋转数组进行二分查找。
题目要求 O(logN) 的时间复杂度,基本可以断定本题是需要使用二分查找,怎么分是关键。
由于题目说数字了无重复,举个例子:
1 2 3 4 5 6 7 可以大致分为两类,
第一类 2 3 4 5 6 7 1 这种,也就是 nums[left] <= nums[mid]。此例子中就是 2 <= 5。
这种情况下,前半部分有序。因此如果 nums[left] <=target<nums[mid],则在前半部分找,否则去后半部分找。
第二类 6 7 1 2 3 4 5 这种,也就是 nums[left] > nums[mid]。此例子中就是 6 > 2。
这种情况下,后半部分有序。因此如果 nums[mid] <target<=nums[right],则在后半部分找,否则去前半部分找。
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;
if (nums[left] <= nums[mid]) {// mid的左半部分升序
if (target < nums[mid] && target >= nums[left])
right = mid - 1;
else
left = mid + 1;
} else {
if (target > nums[mid] && target <= nums[right])
left = mid + 1;
else
right = mid - 1;
}
}
return -1;
}
}
解题思路二 将「旋转数组查找目标值」 转化成 「有序数组查找目标值」
对于旋转数组 nums = [4,5,6,7,0,1,2]
首先根据 nums[0]
与 target
的关系判断 target
是在左段还是右段。
- 例如
target = 5
, 目标值在左半段,因此在[4, 5, 6, 7, inf, inf, inf]
这个有序数组里找就行了; - 例如
target = 1
, 目标值在右半段,因此在[-inf, -inf, -inf, -inf, 0, 1, 2]
这个有序数组里找就行了。
class Solution {
public int search(int[] nums, int target) {
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] == target) {
return mid;
}
// 先根据 nums[0] 与 target 的关系判断目标值是在左半段还是右半段
if (target >= nums[0]) {
// 目标值在左半段时,若 mid 在右半段,则将 mid 索引的值改成 inf
if (nums[mid] < nums[0]) {
nums[mid] = Integer.MAX_VALUE;
}
} else {
// 目标值在右半段时,若 mid 在左半段,则将 mid 索引的值改成 -inf
if (nums[mid] >= nums[0]) {
nums[mid] = Integer.MIN_VALUE;
}
}
if (nums[mid] < target) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
return -1;
}
}
PREVIOUS34. 在排序数组中查找元素的第一个和最后一个位置
NEXT28. 实现 strStr()