[数组] - LeetCode 704. 二分查找

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 - 1left = 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 是否越界
}
相关推荐
shoubepatien2 分钟前
JAVA -- 07
java·后端·intellij-idea
Gu_yyqx4 分钟前
Maven进阶
java·maven
于是我说6 分钟前
前端JavaScript 项目中 获取当前页面滚动位置
开发语言·前端·javascript
小肖爱笑不爱笑6 分钟前
JavaScript
java·javascript·json·web
专注于大数据技术栈7 分钟前
java学习--String和StringBuffer互转
java·学习
2739920298 分钟前
QT5使用QFtp
开发语言·qt
怪力左手23 分钟前
qt qspinbox editingfinished事件问题
开发语言·qt
Ven%24 分钟前
【AI大模型算法工程师面试题解析与技术思考】
人工智能·python·算法
天勤量化大唯粉25 分钟前
枢轴点反转策略在铜期货中的量化应用指南(附天勤量化代码)
ide·python·算法·机器学习·github·开源软件·程序员创富
waper9727 分钟前
nohup java -jar启动jar包错报错 地址已在使用
java·开发语言·jar