二分搜索找第一个小于target的位置等价于std::lower_bound返回位置的前一个索引,需检查是否越界;空数组、单元素等边界情况易出错,应提前判断并返回-1。

二分搜索找第一个小于 target 的位置,本质是找右边界左侧的点
直接结论:这不是标准二分查找的“存在性”或“首个等于”问题,而是「查找插入位置左侧最近的合法位置」,等价于 std::lower_bound 返回位置的前一个索引(需检查是否越界)。关键不是改比较符号,而是重新定义「满足条件」的含义——这里满足条件的是 arr[i] ,我们要找最后一个满足该条件的索引。
手写循环版要注意 mid 更新方向和边界收缩逻辑
常见错误是把 arr[mid] 当作左移条件后,盲目写 <code>left = mid 导致死循环或越界。正确做法是:满足条件时保留 mid,所以让 left = mid;不满足时排除 mid,所以 right = mid - 1。初始 left = 0, right = n - 1,循环用 left ,且必须用向上取整的 <code>mid = left + (right - left + 1) / 2 避免卡在两个元素时无限循环。
- 如果数组全 >= target,结果应为 -1(无合法位置)
- 如果数组全 n - 1
- 返回前必须验证
arr[left] ,否则说明不存在,返回 -1
用 STL 时别直接套 std::lower_bound,要减一再校验
std::lower_bound(first, last, target) 返回第一个 >= target 的迭代器,它的前一个位置才可能是第一个 it - 1 —— 若 it == first,说明所有元素都 >= target,此时 it - 1 是非法迭代器。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 正确写法:
auto it = std::lower_bound(v.begin(), v.end(), target); if (it == v.begin()) return -1; else return it - v.begin() - 1; - 注意:仅当容器支持随机访问(如
vector、array)才能用it - begin()算下标;list不适用 - 若目标值重复出现,这个方法仍正确,因为
lower_bound定位的是左边界,减一就是它左边最后一个合法位置
边界测试最容易漏掉空数组和单元素场景
空数组、单元素且等于 target、单元素且大于 target —— 这三类输入常让手写逻辑崩溃。例如空数组时 right = -1,进入循环前就要判断;单元素时若 arr[0] >= target,应直接返回 -1,而不是进循环后错判。
立即学习“C++免费学习笔记(深入)”;
- 测试用例建议覆盖:
{}、{5}(target=5/6/4)、{1,3,5,7}(target=0/1/2/8) - 用
assert或单元测试快速验证返回值是否在[-1, n-1]范围内,且满足ret == -1 || arr[ret] - 不要依赖“看起来能跑通”,二分的边界错误往往只在特定长度触发
真正麻烦的不是写对一次,而是每次改逻辑都要重验所有边界组合。建议把校验逻辑单独抽出成函数,比反复调试循环变量更省时间。

















