给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3] 和 [2,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
合并区间:
合并区间的基本思路是首先按照区间的起始位置进行排序。(这个就是区间合并的核心了)
然后依次遍历每个区间,如果当前区间的起始位置在目前区间的范围内(不一定是上一个,有可能前几个的右区间大于上一个的右区间),则将两个区间合并成一个;如果当前区间的起始位置在前一个区间的范围外,则将当前区间添加到结果集中,并更新当前区间为新的待比较区间。重复这一过程直到遍历完所有区间。
这种方法的时间复杂度是 O(nlogn),其中 n 是区间的个数,主要由排序操作决定。
代码:
#include <iostream>
#include <algorithm>
#define x first // 定义x为pair的第一个元素
#define y second // 定义y为pair的第二个元素
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII; // 定义PII为pair<int, int>
int n, res = 1; // n为点的个数,res表示最少需要几条线段
PII nums[N]; // 存储点的坐标
int main() {
cin >> n;
for (int i = 0; i < n; i++) // 输入点的坐标
cin >> nums[i].x >> nums[i].y;
sort(nums, nums + n, [](PII a, PII b){ // 按照x坐标从小到大排序
return a.x < b.x;
});
int pd = nums[0].y; // pd表示当前线段的右端点
for (int i = 1; i < n; i++) {
if (pd >= nums[i].x) // 如果当前线段的右端点可以覆盖当前点
pd = max(pd, nums[i].y); // 更新当前线段的右端点
else { // 否则需要增加一条线段
res++;
pd = nums[i].y; // 更新当前线段的右端点
}
}
cout << res; // 输出结果,即最少需要的线段数
}