大家好,今天分享一道经典算法题:搜索旋转排序数组,直接上可运行代码+逐行解释,看完就能吃透思路。
题目描述:整数数组 nums 是一个升序排列的数组,在预先未知的某个下标上进行了旋转,给你目标值 target ,如果数组中存在这个目标值则返回它的下标,否则返回 -1 。
核心代码(直接复制可跑)
var search = function(nums, target) {
// 定义左右指针
let left = 0;
let right = nums.length - 1;
// 标准二分循环条件
while (left <= right) {
// 计算中间下标
let mid = Math.floor((left + right) / 2);
// 找到目标值,直接返回下标
if (nums[mid] === target) {
return mid;
}
// 情况1:左半区间 [left, mid] 是有序的
if (nums[left] <= nums[mid]) {
// target 在左有序区间内,收缩右边界
if (target >= nums[left] && target < nums[mid]) {
right = mid - 1;
} else {
// 否则去右半区间查找
left = mid + 1;
}
}
// 情况2:右半区间 [mid, right] 是有序的
else {
// target 在右有序区间内,收缩左边界
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
} else {
// 否则去左半区间查找
right = mid - 1;
}
}
}
// 循环结束未找到,返回-1
return -1;
};
代码逐行解析
- 双指针初始化:
left指向数组开头,right指向数组末尾,这是二分查找的基础配置。 - 循环条件:
left <= right保证遍历完所有可能的元素。 - 计算中点:
Math.floor((left + right)/2)防止下标溢出,获取中间位置。 - 命中判断:中点值等于目标值,直接返回下标,这是最优情况。
- 判断有序区间:
- 旋转数组一定有一半是有序的,这是解题核心!
nums[left] <= nums[mid]→ 左半段有序- 否则 → 右半段有序
- 收缩区间:根据目标值是否在有序区间内,调整左右指针,缩小查找范围。
- 未找到返回:循环结束都没匹配到,返回
-1。
关键思路总结
这道题的本质:改造版二分查找,利用「旋转数组必有一半有序」的特性,抛弃无序部分,只在有序区间内判断,时间复杂度 O(log n),空间复杂度 O(1)。