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
题解1:二分搜索法
算法理解:
- 相当于总在有序序列中搜索,每次丢弃一半数据,每次只需要判断出在哪一半搜索即可,由于一半总是有序,所以不难做到
- 先根据
nums[mid]
与nums[start]
的关系判断mid
是在左段还是右段,接下来再判断target
是在mid
的左边还是右边,从而来调整左右边界start
和end
。
主要流程思路:
- 类似二分搜索算法,每次计算
mid
,通过比较nums[start]
与nums[mid]
的大小来确定哪一半是有序序列, - 确定有序序列后,再在该区间中判断
target
是否在这个有序区间内, - 若在,切换下标,否则切换下标,继续搜索,
- 最后其总会落到一个
mid
上。
注意:
1.算法中的所有比较建议都加上=
,如<=,>=
,这样不易出错。
2.由于是查找某个值, 所以使用简单二分搜索模板, left<=right
代码:
class Solution {
public int search(int[] nums, int target) {
if (nums.length == 0) return -1; //特例判断
int left = 0, right = nums.length - 1;
while (left <= right) {//注意这里是小于等于
int mid = left + (right - left) / 2;
if (target == nums[mid]) {
return mid;
}
if (nums[left] <= nums[mid]) {//左边有序
if (target >= nums[left] && target <= nums[mid]) {
right = mid - 1; //target落在左边
} else {
left = mid + 1; //否则target 落在右边
}
} else { //右边有序
if (target >= nums[mid] && target <= nums[right]) {//右边有序,且落在右边
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
}
参考:
搜索旋转排序数组 - Java