题目描述
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3][1,3] 和 [2,6][2,6] 可以合并为一个区间 [1,6][1,6]。
输入格式
第一行包含整数 n。
接下来 n行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1≤n≤100000,
−10^9≤li≤ri≤10^9
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
这个代码用到了c++11的特性。
下面是如何在devcpp里面开启c++11:
点击工具
选择编译器选项
选择代码生成,在语言标准处选择ISO C++11即可
区间合并的思想:
先对所有的区间的左端点按从小到大排序,然后从第一个开始依次遍历,每次将当前区间与遍历的区间进行比较和合并,主要有三种情况:
示例代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N= 1e5+10;
int st[N],ed[N]; //起点和终点
int n=0;
//成对出现的数据,对组可以返回两个数据
typedef pair<int,int> PII; //将 pair<int, int> 定义为 PII 类型的别名
vector<PII> segs; //创建一个存放区间的数组
void merge(vector<PII> &segs) //合并区间
{
vector<PII> res; //这是答案
sort(segs.begin(),segs.end()); //先给所有的区间从小到大排序,pair排序优先排左端点,再右端点
int st=-2e9,ed=-2e9; //初始的边界,后面用来纪录当前区间的坐标
for(auto seg:segs) //c++11,seg是循环变量,用于依次表示数组segs中的每个元素
{
if(ed<seg.first) //当前区间右端点小于枚举的区间的左端点,说明找到了一个新的区间
{
if(st!=-2e9) res.push_back({st,ed}); //当st不为初始值时,区间放进答案,实际上题目里的数据全部都不为初始值
st=seg.first,ed=seg.second; //更新区间
}
else //除此之外的情况都是有交集的
{
ed=max(ed,seg.second); //把右端点更新成更右的那一个
}
}
res.push_back({st,ed}); //把最后的合并区间加入数组
//这个最后的合并区间是因为一直在更新右端点而没有触发前面的找到新区间的push_back而存在的,或者是最后枚举的区间与当前区间无交集,此时当前区间被更新为枚举的最后一个区间,但是还没有存入数组之中
segs=res; //把原来传入的区间数组更新
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
int l,r;
cin>>l>>r; //输入一个区间
segs.push_back({l,r}); //向容器末尾添加一个元素,把区间放进segs数组中
}
merge(segs); //区间合并
cout<<segs.size()<<endl; //最后数组里有多少个区间,就是合并后的区间数量
return 0;
}
关于merge函数:
(1)
for (auto seg : segs)
这个for循环用的是c++11的新特性,等同于下面的for循环:
for (int i = 0; i < segs.size(); i++)
{
PII seg = segs[i];
// 处理 seg
}
(2)
if(ed<seg.first) //当前区间右端点小于枚举的区间的左端点,说明找到了一个新的区间
{
if(st!=-2e9) res.push_back({st,ed});
st=seg.first,ed=seg.second;
}
题目给的数据范围是−10^9≤li≤ri≤10^9,也就是枚举的区间一定满足st != -2e9。
这里的st != -2e9主要是为了不要把初始值放进数组,而是更新它的st和ed值。
遍历开始,将当前区间更新为这枚举的第一个区间,然后向后比较,当找到没有交集的区间的时候,把当前区间放进res数组里。
(3)
for(auto seg:segs) //c++11,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); //把右端点更新成更右的那一个
}
}
res.push_back({st,ed}); //把最后的合并区间加入数组
为什么要把最后的合并区间加入数组?这里存在着两种情况,对应着上面的if else判断。
第一种情况是最后枚举的区间满足if(ed<seg.first),此时它之前的合并区间与它没有交集,之前的合并区间被存入数组,而当前区间被更新为了最后枚举的区间,但是它的循环已经结束了,而它还没有pushback存入数组,所以我们将它存入。
第二种情况就是else,最后枚举的区间与之前的合并区间有交集,此时两者取并集更新,得到了一个新的合并区间,而没有pushback存入数组,所以我们也要将它们存入。