左闭右开二分查找:一套模板搞定所有场景

左闭右开二分查找:一套模板搞定所有场景
Garfield左闭右开二分查找:一套模板搞定所有场景
二分查找是算法面试和工程开发中的高频考点,但左闭右闭、左闭右开两种写法容易混淆出错。
今天给大家整理一套彻底统一、零歧义、永不死循环的左闭右开二分模板,背会这一套,所有二分查找问题直接套用,堪称标准答案!
一、核心基础:左闭右开定义
这是理解整个模板的前提,必须牢牢记住:
1. 区间规则
1 | [l, r) |
- 左闭:
l是有效下标,可以取到 - 右开:
r是边界下标,永远取不到
2. 初始化写法
1 | int l = 0; // 左边界:数组起始位置 |
二、万能通用模板(背诵版)
所有二分查找的核心骨架,直接背!
1 | // 初始化:左闭右开 [0, nums.length) |
三、模板核心逻辑:找「左边界」
这套左闭右开模板的本质:
查找第一个满足条件的元素位置(左边界)
最经典场景:查找第一个大于等于 target 的位置
1 | // lower_bound:第一个 >= target 的位置 |
四、全场景对照表(重点!)
只需要修改判断条件,就能适配所有二分需求,直接查表使用:
| 查找目标 | 判断条件 | 区间收缩规则 | 返回值 |
|---|---|---|---|
| 第一个 ≥ target(左边界) | nums[mid] < target |
l=mid+1 / r=mid |
l |
| 第一个 > target | nums[mid] <= target |
l=mid+1 / r=mid |
l |
| 最后一个 ≤ target | 转换:upper_bound - 1 | 同上 | l - 1 |
| 最后一个 < target | 转换:lower_bound - 1 | 同上 | l - 1 |
关键总结:判断条件为 nums[mid] < target则l为第一个大于target的值,判断条件为 nums[mid] <= target则l为第一个大于target的值
五、关键理解:为什么只返回 l?
很多人纠结这个点,其实一句话就能懂:
- 循环条件是
while (l < r) - 循环结束时,一定满足
l == r - 整个区间收缩成了唯一的一个点,这个点就是答案
所以:
- 返回
l和r效果完全一样 - 统一习惯返回
l即可
六、左闭右开核心思想:保留可能解
这是左闭右开最不容易写错的关键:
r永远是「可能答案」的上界,且不能丢弃候选值
所以代码中一定是:
1 | r = mid; // 绝对不要写 r = mid - 1 |
原因:
mid有可能就是最终答案- 必须保留这个候选值,不能直接排除
七、高频两个模板:lower_bound /upper_bound
面试和刷题最常用的两个标准实现,直接复制用:
1. lower_bound(第一个 ≥ target)
1 | public int lowerBound(int[] nums, int target) { |
2. upper_bound(第一个 > target)
1 | public int upperBound(int[] nums, int target) { |
八、左闭右开 VS 左闭右闭(核心区别)
| 写法 | 区间 | 循环条件 | 返回值 |
|---|---|---|---|
| 左闭右闭 | [l, r] |
l <= r |
需分情况判断 |
| 左闭右开 ✅ | [l, r) |
l < r |
永远返回 l |
✅ 结论:
左闭右开写法更统一、逻辑更简洁、几乎不会出现死循环,这也是大厂优先推荐的原因。
九、一句话总结(面试必背)
左闭右开二分查找:通过 r = mid 保留可能解,最终区间收缩到 l == r,答案就是 l。
总结
- 统一用
[l, r)左闭右开 区间,初始化r = 数组长度 - 循环条件固定
l < r,永不死循环 - 收缩规则:满足条件
l = mid + 1,不满足r = mid - 最终答案永远返回 l
- 两套核心模板:
lower_bound/upper_bound,覆盖所有场景
这套模板吃透,面试 / 刷题二分查找直接秒杀!
评论
匿名评论隐私政策
✅ 你无需删除空行,直接评论以获取最佳展示效果






