区间合并的介绍:
给定一些区间,输出这些区间整体的区间范围。
比如:
有区间 [ 1 , 2 ] [ 1 , 3 ] [ 2 , 4 ] [ 5 , 6 ] [ 6 , 8 ]
那么合并后的区间就是 [ 1 , 4 ] [ 5 , 8 ]
核心思想:
将所有区间按 左边界 从小到大 排序
用两个变量 l 和 r 维护当前区间,然后遍历整个排好序后的区间集合
如果用 [ l , r ] 表示当前区间, [ a , b ] 表示下一个区间,则一共有下面三种情况:
1、 a > r 说明两个区间没有交集,那就直接把 [ l , r ] 这个区间存入容器中。
因为已经按左边界排序过了,后面的区间也不可能和 [ l , r ] 有交集。
[ l , r ] 这个区间就是一个孤立的区间了。
2、 a < r 且 b < r 说明 [ a , b ] 在 [ l , r ] 内,l 和 r 的值就不需要改变
3、 a < r 且 b > r 说明两个区间有部分交集,合并后整个区间变长了,所以
r 的值需要变:r = b,整个区间变为:[ l , b ]
其中,后面两种情况可以合在一起写: r = max ( r , b );
具体例子(一定要看):
题目:现输入 n 个区间 [ l , r ],输出合并后的区间。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int, int> PII; // 用 pair 存储区间
const int N = 100010, INF = 1e9; // INF 是无穷大的意思
int n;
vector<PII> v; // v 用来存储所有的区间
// 合并区间的主要操作
void merge(vector<PII>& v){
vector<PII> res; // res 存储合并后的区间
sort(v.begin(), v.end()); // 按 “左边界” 从小到大排序
int l = -INF, r = -INF; // 初始让左右边界都为无穷小
for (auto i : v){
if (i.first > r){ // 说明 i 这个区间和当前的区间没有交集
// 如果是第一个区间就不放入,不是第一个区间就放入
if (l != -INF)
res.push_back({l, r});
l = i.first, r = i.second; // 更新当前区间
}
// 如果有交集,就让有边界取两者最远的那个
else r = max(r, i.second);
}
res.push_back({l, r}); // 最后一个区间需要手动放入
v = res; // 原来存储区间的 v = 新存储的区间
}
int main(){
cin >> n;
// 读入 n 个区间,全部放进容器 v 中
while (n--){
int l, r;
cin >> l >> r;
v.push_back({l, r});
}
merge(v);
// 输出
for (auto i : v)
cout << i.first << ' ' << i.second << endl;
return 0;
}