题解:AcWing 803 区间合并
【题目来源】
AcWing:803 区间合并 - AcWing题库
【题目描述】
给定 \(n\) 个区间 \([l_i,r_i]\),要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:\([1,3]\) 和 \([2,6]\) 可以合并为一个区间 \([1,6]\)。
【输入】
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含两个整数 \(l\) 和 \(r\)。
【输出】
共一行,包含一个整数,表示合并区间完成后的区间个数。
【输入样例】
5
1 2
2 4
5 6
7 8
7 9
【输出样例】
3
【核心思想】
-
问题分析:给定 \(n\) 个区间 \([l_i, r_i]\),需要将所有有交集(包括端点相交)的区间合并,输出合并后的区间个数。这是一个经典的区间合并问题,关键在于如何高效地识别和合并相交区间。
-
算法选择:
- 贪心策略(Greedy):通过排序将相交区间聚集在一起,然后线性扫描合并
- 按左端点排序:将所有区间按照 \(l_i\) 从小到大排序,这样相交的区间会被排列在相邻位置
- 维护当前合并区间:使用变量 \(st\) 和 \(ed\) 维护当前正在合并的区间起始和结束位置
-
关键步骤:
- 读取输入:\(n\)(区间数量)、\(n\) 个区间 \([l_i, r_i]\)
- 按左端点排序:使用
sort(segs.begin(), segs.end())按左端点升序排序 - 初始化合并区间:
st = -2e9, ed = -2e9(表示当前无合并区间) - 遍历合并(遍历每个区间 \([l, r]\)):
- 无交集情况(
ed < l):当前区间与合并区间无交集- 如果不是第一个区间,将 \([st, ed]\) 加入结果
- 开始新区间:
st = l, ed = r
- 有交集情况(
ed >= l):当前区间与合并区间有交集- 合并区间:
ed = max(ed, r)
- 合并区间:
- 无交集情况(
- 处理最后一个区间:将最后一个合并区间加入结果
- 输出结果:合并后的区间个数
-
时间/空间复杂度:
- 时间复杂度:\(O(n \log n)\),排序 \(O(n \log n)\),遍历合并 \(O(n)\)
- 空间复杂度:\(O(n)\),存储区间和合并结果
-
区间合并的核心思想:
- 排序预处理:按左端点排序是区间问题的基础,将相交区间聚集在一起
- 贪心合并策略:维护当前合并区间的最右端点 \(ed\),与新区间的左端点 \(l\) 比较判断是否相交
- 边界处理:端点相交(
ed == l)也算有交集,因此判断条件为ed < l而非ed <= l - 扫描线思想:线性扫描已排序的区间,每次处理一个区间,时间复杂度线性
- 适用于区间重叠检测、区间覆盖、日程安排等问题
【解题思路】

【算法标签】
贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII; // 定义区间类型
const int N = 100010;
int n; // 区间个数
vector<PII> segs; // 存储所有区间
// 区间合并函数
void merge(vector<PII> &segs)
{
vector<PII> res; // 存储合并后的结果
sort(segs.begin(), segs.end()); // 按左端点排序
int st = -2e9, ed = -2e9; // 当前合并区间的起始和结束
for (auto seg : segs) // 遍历所有区间
{
if (ed < seg.first) // 当前区间与合并区间无交集
{
if (st != -2e9) // 如果不是第一个区间
{
res.push_back({st, ed}); // 保存前一个合并区间
}
st = seg.first, ed = seg.second; // 开始新的合并区间
}
else // 当前区间与合并区间有交集
{
ed = max(ed, seg.second); // 合并,更新右端点
}
}
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(segs); // 合并区间
cout << segs.size() << endl; // 输出合并后的区间个数
return 0;
}
【运行结果】
5
1 2
2 4
5 6
7 8
7 9
3
浙公网安备 33010602011771号