C++中的 lower_bound 和 upper_bound:一篇讲清楚

在刷题或者写代码的时候,lower_boundupper_bound 是两个非常高频但又容易用错的函数。很多人知道"能用",但不知道"为什么这样用"。

这篇文章不搞花里胡哨的定义,直接从实际理解、使用方式、常见坑这几个角度讲清楚。


这两个函数到底是干嘛的;一句话版本

在一个有序序列中:

  • lower_bound:找到 第一个 >= x 的位置

  • upper_bound:找到 第一个 > x 的位置

记住这句话基本就够用了。


举个最简单的例子

复制代码
vector<int> v = {1, 2, 2, 2, 3, 4};

查找 2

复制代码
lower_bound(v.begin(), v.end(), 2) → 指向第一个 2  
upper_bound(v.begin(), v.end(), 2) → 指向第一个 3

也就是说:

复制代码
lower_bound → 左边界  
upper_bound → 右边界

返回的是什么;别搞错了

这两个函数返回的不是下标,而是:

迭代器(iterator)

如果你要下标,需要这样写:

复制代码
int pos = lower_bound(v.begin(), v.end(), x) - v.begin();

最常见用途一;判断元素是否存在

复制代码
auto it = lower_bound(v.begin(), v.end(), x);

if (it != v.end() && *it == x) {
    cout << "存在";
}

解释:

  • lower_bound 找到第一个 >= x 的位置

  • 如果这个位置刚好等于 x → 说明存在


最常见用途二;统计某个数出现次数

复制代码
int cnt = upper_bound(v.begin(), v.end(), x) 
        - lower_bound(v.begin(), v.end(), x);

这行代码非常经典,直接记住:

出现次数 = 右边界 - 左边界


最常见用途三;插入位置

如果你要往有序数组中插入一个元素:

复制代码
auto it = lower_bound(v.begin(), v.end(), x);
v.insert(it, x);

这样插入之后,数组依然有序。


必须注意的前提;一定要有序

这两个函数的前提是:

序列必须是有序的(默认升序)

如果是乱序数组:

  • 结果是错的

  • 但不会报错(这是最坑的地方)


自定义排序怎么办

如果你用的是自定义排序,比如降序:

复制代码
sort(v.begin(), v.end(), greater<int>());

那你就必须传入同样的比较函数:

复制代码
lower_bound(v.begin(), v.end(), x, greater<int>());

否则结果是错误的。


手写理解;它本质就是二分

可以用一个简单的"手写版本"来理解 lower_bound:

复制代码
int l = 0, r = n;
while (l < r) {
    int mid = (l + r) / 2;
    if (v[mid] >= x) r = mid;
    else l = mid + 1;
}

最终:

复制代码
l 就是 lower_bound 的位置

而 upper_bound 只是把条件改成:

复制代码
v[mid] > x

常见坑总结

; 忘了数组必须有序

很多人直接用在乱序数组上,结果完全不对

; 把返回值当下标

记住它返回的是迭代器

; 边界没判断

复制代码
it != v.end()

一定要写

; 自定义排序没传比较函数

这是中高级选手最容易翻车的地方


一句话记忆法

如果你懒得记一堆东西,就记这一句:

lower_bound 找"第一个不小于",upper_bound 找"第一个大于"


最后

这两个函数本质上就是"封装好的二分查找",但它们的威力在于:

  • 写法简洁

  • 不容易出错

  • 能直接解决很多区间问题

建议你多用几次,比如:

  • 统计区间

  • 去重处理

  • LIS(最长上升子序列)

用多了,自然就顺手了。

相关推荐
郝学胜-神的一滴5 分钟前
[简化版 GAMES 101] 计算机图形学 04:二维变换上
c++·算法·unity·godot·图形渲染·unreal engine·cesium
ZC跨境爬虫5 分钟前
海南大学交友平台开发实战day7(实现核心匹配算法+解决JSON请求报错问题)
前端·python·算法·html·json
迷藏4948 分钟前
**发散创新:基于角色与属性的混合权限模型在微服务架构中的实战落地**在现代分布式系统中,
java·python·微服务·云原生·架构
计算机安禾10 分钟前
【数据结构与算法】第41篇:图论(五):拓扑排序与关键路径
c语言·数据结构·c++·算法·图论·visual studio
Q741_14713 分钟前
每日一题 力扣 1320. 二指输入的的最小距离 动态规划 C++ 题解
c++·算法·leetcode·动态规划
码以致用16 分钟前
Java垃圾回收器笔记
java·jvm·笔记
暴力袋鼠哥18 分钟前
基于springboot与vue的ai多模态数据展示看板
java·spring boot
wfbcg21 分钟前
每日算法练习:LeetCode 76. 最小覆盖子串 ✅
算法·leetcode·职场和发展
Wect25 分钟前
LeetCode 149. 直线上最多的点数:题解深度剖析
前端·算法·typescript
用户83071968408227 分钟前
VS Code Java开发配置与使用经验分享
java·visual studio code