[数组] - 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 - 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 是否越界
}
相关推荐
leobertlan3 小时前
痛苦系列 | DSP-03 跨越单位圆:Z变换与零极点分析
算法·程序员
蛋蛋的就会顺顺的3 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
需要8264 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
开发小能手1234 小时前
答案daanC语言
数据结构·算法
小 黄 鸡4 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
死磕音视频5 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
Navigator_Z5 小时前
LeetCode //C - 1291. Sequential Digits
c语言·算法·leetcode
伯恩bourne6 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
silvamux_6 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
pride.li7 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉