区间合并

600 字
3 分钟
区间合并

区间合并#

区间合并用来处理多个区间之间的重叠关系。

比如:

[1, 3] 和 [2, 4]

这两个区间有交集,可以合并成:

[1, 4]

1、问题描述#

给出若干个区间,要求把所有有交集的区间合并,最后得到互不重叠的区间。

例如:

[1, 3] [2, 6] [8, 10] [9, 12]

合并后:

[1, 6] [8, 12]

2、核心思路#

区间合并一般分两步:

1. 按左端点从小到大排序
2. 从前往后维护当前正在合并的区间 [st, ed]

排序后,只需要看当前区间和维护区间是否相交。

3、如何判断是否相交#

假设当前维护区间是:

[st, ed]

新来的区间是:

[l, r]

如果:

ed < l

说明两个区间完全分开,需要开启一个新区间。

否则说明有交集,可以合并:

ed = max(ed, r)

4、C++ 模板#

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
int n;
vector<PII> segs;
void merge_segments(vector<PII>& segs) {
vector<PII> res;
sort(segs.begin(), segs.end());
int st = -2e9;
int ed = -2e9;
for (auto seg : segs) {
int l = seg.first;
int r = seg.second;
if (ed < l) {
if (st != -2e9) res.push_back({st, ed});
st = l;
ed = r;
} else {
ed = max(ed, r);
}
}
if (st != -2e9) res.push_back({st, ed});
segs = res;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
int l, r;
cin >> l >> r;
segs.push_back({l, r});
}
merge_segments(segs);
cout << segs.size() << endl;
return 0;
}

5、手推一遍#

输入:

[1, 3] [2, 6] [8, 10] [9, 12]

先排序,顺序不变。

处理 [1, 3]:

当前区间 = [1, 3]

处理 [2, 6],因为 2 <= 3,有交集:

当前区间 = [1, 6]

处理 [8, 10],因为 6 < 8,开启新区间:

保存 [1, 6]
当前区间 = [8, 10]

处理 [9, 12],有交集:

当前区间 = [8, 12]

最后保存 [8, 12]。

6、容易写错的地方#

(1)忘记先排序#

不排序的话,无法保证只和当前维护区间比较就够了。

(2)最后一个区间忘记加入答案#

循环结束后还要:

if (st != -2e9) res.push_back({st, ed});

(3)相邻端点是否合并要看题意#

当前模板中:

if (ed < l)

表示 [1, 3] 和 [3, 5] 会合并。

如果题目认为端点相接不算重叠,就要改成:

if (ed <= l)

总结#

区间合并的关键词是:

按左端点排序 + 维护当前右端点

只要能判断新区间是否和当前区间相交,代码就很直接。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

区间合并
https://blog.tjcheng.cn/posts/migrated/old-83/
作者
TengJinCheng
发布于
2025-10-05
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
TengJinCheng
Hello, I'm Teng.
公告
欢迎来到TengJinCheng工作铺!
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
分类
标签
站点统计
文章
157
分类
7
标签
114
总字数
109,939
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.4
文章许可
CC BY-NC-SA 4.0

文章目录