LeetCode 33. 搜索旋转排序数组:二分查找的边界艺术
文章目录
- 问题描述
- 解决思路
- 代码实现
- 关键点解析
- 1. 为什么用 `nums[left] <= nums[mid]`?
- 2. 示例分析
- 案例 1:数组 `[3, 1]`,目标值 `1`
- 案例 2:数组 `[5]`,目标值 `5`
- 边界条件处理
- 1. 单元素数组
- 2. 完全有序数组
- 3. 严格递增与重复值
- 常见疑问
- Q:为什么不能使用 `nums[left] < nums[mid]`?
- 总结
问题描述
在旋转后的有序数组中搜索目标值。假设数组原本按升序排列,但在某个未知下标处进行了旋转(例如 [0,1,2,4,5,6,7]
旋转后可能变为 [4,5,6,7,0,1,2]
)。要求时间复杂度为 O(log n)。
示例:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
解释:目标值 0 位于旋转后的右半部分。
解决思路
旋转后的数组可视为两个有序子数组的组合。利用 二分查找 的关键在于判断哪一部分是有序的,并检查目标值是否在该范围内。核心步骤如下:
- 判断有序区间:通过比较
nums[left]
和nums[mid]
,确定左半或右半是否有序。 - 缩小搜索范围:根据目标值是否在有序区间内,调整左右指针。
代码实现
class Solution {public int search(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] == target) return mid; // 直接命中// 判断左半部分是否有序if (nums[left] <= nums[mid]) { // 目标值在左半有序区间内if (target >= nums[left] && target < nums[mid]) {right = mid - 1;} else {left = mid + 1;}} else { // 右半部分有序// 目标值在右半有序区间内if (target > nums[mid] && target <= nums[right]) {left = mid + 1;} else {right = mid - 1;}}}return -1;}
}
关键点解析
1. 为什么用 nums[left] <= nums[mid]
?
- 判断有序区间:
若nums[left] <= nums[mid]
,说明左半部分[left, mid]
是有序的(未包含旋转点)。否则右半部分有序。 - 边界处理:
当left == mid
时(例如数组长度为 1),nums[left] == nums[mid]
,等号确保这种情况被正确归类为“左半有序”。
2. 示例分析
案例 1:数组 [3, 1]
,目标值 1
left = 0
,mid = 0
,满足nums[left] <= nums[mid]
(3 ≤ 3)。- 目标值不在左半部分(1 < 3 不成立),调整
left = mid + 1
,最终找到目标值。
案例 2:数组 [5]
,目标值 5
- 若去掉等号,条件
nums[left] < nums[mid]
不成立,程序误判右半有序。 - 检查右半部分时,
target > nums[mid]
不成立,错误调整right = mid - 1
,导致返回-1
。
边界条件处理
1. 单元素数组
当 nums.length == 1
时,left == mid == right
,必须通过等号确保逻辑正确。
2. 完全有序数组
若数组未旋转(例如 [1,2,3,4,5]
),逻辑仍能正确判断左半有序。
3. 严格递增与重复值
题目假设元素唯一,无需处理重复值。若存在重复值需调整条件(如 nums[left] < nums[mid]
)。
常见疑问
Q:为什么不能使用 nums[left] < nums[mid]
?
- 边界问题:当
left == mid
时,条件不成立,导致误判右半有序。 - 错误示例:
数组[5]
,目标值5
。若用<
,程序错误调整right = mid - 1
,最终返回-1
。
总结
- 核心逻辑:通过
nums[left] <= nums[mid]
判断有序区间,结合目标值范围调整指针。 - 边界条件:等号处理
left == mid
的临界情况,确保单元素区间被正确识别。 - 时间复杂度:O(log n),每次循环将搜索范围减半。
关键启示:二分查找的难点不仅在于算法框架,更在于对边界条件的精准处理。理解每一行代码背后的意图,才能避免“差之毫厘,谬以千里”。