题目描述
给定 n 个区间 $[l_i,r_i]$,要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3]和[2,6]可以合并为一个区间[1,6]。
输入格式
第一行包含整数n。
接下来n行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
$1≤n≤100000$,
$10^{-9}≤l_i≤r_i≤10{9}$
输入样例
5
1 2
2 4
5 6
7 8
7 9
输出样例
3
算法
首先构造一个pair数组,存储所有区间,然后使用sort()函数对其排序,时间复杂度为$O(nlogn)$,之后对数组进行遍历,时间复杂度为$O(n)$。
关键点在于对数组的遍历,使用 $sort()$ 排序后,可以保证数组中的pair按照左区间大小升序排列,在处理时,需要设置一个变量 $maxr$ 存储当前遍历到的最大右端点,只需判断当前pair的左端点是否小于已遍历pair的最大右端点。这句话是此题的关键,只要满足此条件,必然能够进行区间合并。若不满足,则区间总数++,开始搜索下一个区间,并更新 $maxr$ 的值为当前右端点。
时间复杂度 $O(nlogn)$
C++ 代码
#include <iostream>
#include <vector>
#include <algorithm>
#define l first
#define r second
using namespace std;
typedef pair<int, int> pii;
int n, x, y, res = 0, k = 0;
vector<pii> vec;
int main() {
scanf("%d", &n);
if(n == 1) {
printf("0\n");
return 0;
}
for (int i = 0; i < n; i ++) {
scanf("%d%d", &x, &y);
vec.push_back({x, y});
}
sort(vec.begin(), vec.end());
int maxr = vec[0].l;
for(int i = 1; i < n; i ++) {
pii cur = vec[i], last = vec[i-1];
maxr = max(maxr, last.r);
if(cur.l <= maxr) k ++;
else k = 1;
if(k == 1) {
maxr = cur.l;
res ++;
}
}
printf("%d\n", res);
return 0;
}