[数组] - 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 是否越界
}
相关推荐
陈小桔几秒前
logging模块-python
开发语言·python
消失的旧时光-19431 分钟前
函数指针 + 结构体 = C 语言的“对象模型”?——从 C 到 C++ / Java 的本质统一
linux·c语言·开发语言·c++·c
mit6.8241 分钟前
出入度|bfs|状压dp
算法
!停2 分钟前
C语言栈和队列的实现
开发语言·数据结构
xiaobaishuoAI2 分钟前
后端工程化实战指南:从规范到自动化,打造高效协作体系
java·大数据·运维·人工智能·maven·devops·geo
hweiyu002 分钟前
强连通分量算法:Kosaraju算法
算法·深度优先
源代码•宸3 分钟前
Golang语法进阶(定时器)
开发语言·经验分享·后端·算法·golang·timer·ticker
期待のcode4 分钟前
TransactionManager
java·开发语言·spring boot
郝学胜-神的一滴5 分钟前
Linux系统编程:深入理解读写锁的原理与应用
linux·服务器·开发语言·c++·程序人生
Larry_Yanan5 分钟前
Qt多进程(十一)Linux下socket通信
linux·开发语言·c++·qt