LeetCode 704. 二分查找
本题的核心在于统一搜索区间的定义 ------始终将区间视为闭区间 [left, right],并确保循环条件与区间更新逻辑严格匹配。
java
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1; // 闭区间 [left, right]
while (left <= right) { // 区间非空时继续
int mid = (left + right) >> 1;
if (target < nums[mid]) {
right = mid - 1; // 更新右边界(排除 mid)
} else if (nums[mid] < target) {
left = mid + 1; // 更新左边界(排除 mid)
} else {
return mid; // 命中目标
}
}
return -1; // 未找到
}
}
进阶思考:二分查找的边界陷阱与两种区间定义
1. 为什么推荐闭区间 [left, right]?
闭区间定义具有以下优势:
- 语义直观 :
left <= right直接对应"区间非空"的数学定义 - 边界处理自然 :
right = mid - 1和left = mid + 1的更新逻辑与区间定义完全一致 - 避免死循环 :不会出现
left == right时无法退出的情况
2. 开区间 (left, right) 的写法对比
若采用左闭右开区间 [left, right),需要调整:
java
int left = 0, right = nums.length; // 注意 right 初始值
while (left < right) { // 区间非空条件变为 <
int mid = left + (right - left) / 2;
if (target < nums[mid]) {
right = mid; // 关键区别:保持右开
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
3. 高频错误场景
错误1:边界溢出
java
// 错误写法(当 left + right 可能溢出时)
int mid = (left + right) / 2;
// 正确写法
int mid = left + (right - left) / 2;
错误2:区间更新逻辑矛盾
java
// 错误:区间定义为 [left, right] 但更新为 right = mid
if (target < nums[mid]) {
right = mid; // 此时 mid 仍在区间内,可能导致死循环
}
4. 模板扩展:寻找左右边界
寻找左边界(第一个 ≥ target 的位置)
java
int leftBound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (target <= nums[mid]) {
right = mid - 1; // 保留 mid 作为候选
} else {
left = mid + 1;
}
}
return left; // 需检查 left 是否越界
}
寻找右边界(最后一个 ≤ target 的位置)
java
int rightBound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1; // 保留 mid 作为候选
}
}
return right; // 需检查 right 是否越界
}