双指针法可在O(m+n)时间内求两个有序vector的交集,核心是同步推进两指针:元素不等时小者进一,相等时加入结果并双进;需防范越界访问。

用双指针遍历两个有序vector
两个 vector 已排序时,交集可以严格在 O(m + n) 时间内完成,不需要哈希或二分——核心是维护两个下标,像归并排序的合并阶段那样推进。
关键逻辑:比较当前两元素,小的向前走;相等就加入结果,并同时推进两个指针。
常见错误现象:std::vector::push_back 前没预留空间不影响正确性,但频繁扩容可能影响性能;更隐蔽的是越界访问——比如只检查 i 却忘了 <code>j 。
- 必须同时判断两个索引是否越界,任一越界即终止
- 相等时要 先记录再同步递增,否则会漏掉连续重复值(如
{1,1,2}∩{1,1,3}) - 如果输入允许重复且要求交集去重(如数学定义),需跳过相邻重复值;若保留重复(如多重集交集),则每次相等都记录
处理含重复元素的交集语义
“交集”在不同场景含义不同:std::set_intersection 默认按多重集语义(保留重复),而数学集合交集应去重。C++ 标准库不自动去重,得自己控制。
立即学习“C++免费学习笔记(深入)”;
示例:若 a = {1,1,2,2,3}, b = {1,2,2,4}:
- 多重集交集 →
{1,2,2}(每个元素取 min(出现次数)) - 集合交集 →
{1,2}(每个元素最多一次)
实现集合交集时,在记录相等元素后,需跳过 a 和 b 中后续相同值:
while (i + 1 < a.size() && a[i + 1] == a[i]) ++i; while (j + 1 < b.size() && b[j + 1] == b[j]) ++j;
直接调用 std::set_intersection 的前提与陷阱
std::set_intersection 要求输入迭代器范围已排序,且输出容器需提前分配空间或使用插入迭代器;它默认按多重集规则工作,不自动去重。
容易踩的坑:
- 输出
vector没 resize 或用back_inserter,直接传res.begin()会导致越界写入 - 传入的两个 range 不满足
operator<全序(比如自定义类型未正确定义<),行为未定义 - 输入非严格升序(含相等元素没问题),但若为降序,必须传
std::greater<int>()作为第5个参数
安全写法:
vector<int> res; res.reserve(min(a.size(), b.size())); set_intersection(a.begin(), a.end(), b.begin(), b.end(), back_inserter(res));
性能和兼容性注意事项
双指针手写比 std::set_intersection 更易调试、可控性强,尤其当需要定制重复处理或早期退出(如只要前3个交集元素)时。
但要注意:
- 若 vector 很小(
-
std::set_intersection在 libc++/MSVC 中可能有 SIMD 优化,大数组时未必慢于手写 - 所有方案都要求输入已排序;若不确定,先调
std::is_sorted断言,而非静默错用
最常被忽略的一点:两个 vector 的 value_type 必须可比较,且比较结果一致——比如 float 向量用 == 判等可能因精度失效,此时需自定义谓词并确保与排序所用谓词兼容。


















