[数组] - 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 是否越界
}
相关推荐
剑挑星河月2 分钟前
94.二叉树的中序遍历
java·算法·leetcode
拳里剑气3 分钟前
C++算法:队列与BFS
c++·算法·bfs·宽度优先·队列
2301_801184758 分钟前
docker 工作
java·docker·容器
老前端的功夫17 分钟前
【Java从入门到入土】47:构建工具:Maven与Gradle的战争
java·python·maven
aaPIXa62219 分钟前
C++模板元编程:在编译期完成计算,实现零运行时开销
java·开发语言·c++
Ivanqhz24 分钟前
注意力机制
线性代数·算法·矩阵·哈希算法·dnn
z小猫不吃鱼28 分钟前
02 Optimal Brain Damage 详解:二阶信息剪枝的起点
算法·机器学习·剪枝
Keven_1130 分钟前
算法札记:如何判断一个DP能否单调队列优化
算法
m0_6265352038 分钟前
近似attention
人工智能·算法·机器学习
夜郎king42 分钟前
RuoYi-Vue3 企业级后台快速落地实战指南
java·开发语言