文章目录
题目描述
- 给定
n
个区间[li,ri]
,要求合并所有有交集的区间。 - 注意如果在端点处相交,也算有交集。
- 输出合并完成后的区间个数。
- 例如:
[1,3]
和[2,6]
可以合并为一个区间[1,6]
。
输入格式
- 第一行包含整数
n
。 - 接下来
n
行,每行包含两个整数l
和r
。
输出格式
- 共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1 ≤ n ≤ 100000
,−10^9 ≤ li ≤ ri ≤ 10^9
基本思路
本题的思路如下:
- 将所有的区间按照左端点从小到大的顺序进行排序;
- 取出当前的第一个区间,并判断其与后面的一个区间是否有交集。排序后,一个区间和其后面的一个区间只有三种可能的容斥关系(这是因为后一个区间的左端点一定在当前区间的左端点处或更右边):后面一个区间包含在前一个区间中、后面一个区间和前一个区间有交集但是互不包含、后面一个区间与前面的区间没有相交的元素。
- 如果后面一个区间与当前区间有交集,则求出两个区间的并集,更新当前包含该区间的最大合并区间;如果后面一个区间与当前区间没有交集,则说明后面一个区间的左端点在当前合并区间的右端点的右侧,则将当前的合并区间作为最终的一个合并区间放入结果集合中,然后取出后面一个区间重复上述过程。
解题代码
cpp
#include <cstdio>
#include <utility>
#include <vector>
#include <algorithm>
using namespace std;
vector<pair<int, int> > intervals;
vector<pair<int, int> > merge_result;
int main(void)
{
int n;
scanf("%d", &n);
for(int i(0); i < n; ++i)
{
int left, right;
scanf("%d%d", &left, &right);
intervals.push_back({left, right});
}
sort(intervals.begin(), intervals.end());
int left = -2e9, right = -2e9;
for(auto item : intervals)
{
// 当前遍历到的区间是否与局部合并的区间无相交的情况,则添加一个结果
if(item.first > right)
{
if(right != -2e9) merge_result.push_back({left, right});
left = item.first;
right = item.second;
}
// 当前遍历到的区间与局部合并的区间有相交
else right = max(right, item.second);
}
//将最终的结果放入,考虑到输入为空的情况,需要增加一条判定
if(left != -2e9 && right != -2e9) merge_result.push_back({left, right});
printf("%d", merge_result.size());
return 0;
}
其他说明:
- 在C++中,
pair
类型的向量使用sort
函数进行排序时,会根据每个有序对的第一个元素进行排序。