需要找第一个大于目标的值时,适用于离散化坐标、计算插入位置、求上界等场景;此时应改用upper_bound语义,调整边界条件为left
什么时候需要找第一个大于目标的值
不是所有二分场景都为“等于”。比如在离散化坐标、计算插入位置、求上界(upper_bound 语义)时,你需要的是
std::upper_bound的行为:返回第一个严格大于target的元素位置。标准库有现成函数,但手写时容易错在边界处理和终止条件。手写二分时怎么改标准模板
标准二分查找(找等于)的循环条件是
left ,而找“第一个大于”必须用 <code>left ,且始终维护「答案在 <code>[left, right]内」这一不变式。关键改动点:
- 初始化:
left = 0,right = nums.size()(注意不是size()-1),因为答案可能在末尾之后(即插入末尾)- 判断逻辑:当
nums[mid] 时,说明 <code>mid及左边都不满足“大于”,所以left = mid + 1- 否则(
nums[mid] > target),mid是候选答案,但左边可能还有更小的满足位置,所以right = mid- 循环结束时,
left == right,即为第一个大于target的下标示例代码:
int upper_bound(vector<int>& nums, int target) { int left = 0, right = nums.size(); while (left <h3>常见错误:越界、死循环、返回值理解偏差</h3> <p>最容易踩的坑不是逻辑,而是对返回值的误用:</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a> <p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p> </div> <a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> <ul> <li>返回 <code>left</code> 而不是 <code>nums[left]</code> —— 函数应返回下标,调用者自己取值;若直接返回 <code>nums[left]</code>,当 <code>left == nums.size()</code> 时会越界</li> <li>把 <code>right</code> 初始化为 <code>nums.size() - 1</code>,导致无法表达“插入末尾后”的情况</li> <li>用 <code>left + <code>return left</code> 混搭,容易在 <code>left == right</code> 时多算一次,或漏掉边界</code> </li> <li>没考虑空数组:若 <code>nums.empty()</code>,直接返回 <code>0</code> 是正确行为(插入位置为 0)</li> </ul> <h3>和 <code>std::upper_bound</code> 的行为是否完全一致</h3> <p>完全一致。C++ 标准库的 <code>std::upper_bound</code> 就是返回第一个大于 <code>target</code> 的迭代器,其底层实现正是上述逻辑。你可以用它验证手写版本:</p> <pre class="brush:php;toolbar:false;">auto it = std::upper_bound(nums.begin(), nums.end(), target); assert(upper_bound(nums, target) == it - nums.begin());注意:该算法要求输入已升序,不检查,也无稳定排序保证;若含重复值,它跳过所有等于
target的元素,停在第一个更大的位置 —— 这正是你要的“第一个大于”语义。边界情况多,但核心就一条:维护左闭右开区间,只动
left或right,不动摇不变式。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











