题目描述
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3]和[2,6]可以合并为一个区间[1,6]。
输入格式
第一行包含整数n。
接下来n行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1≤n≤100000,
−109≤li≤ri≤109
样例
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
算法一
贪心按左端点水过
思路:
就是以左端点进行排序,每次让下一个集合与该集合的右端点进行比较即可。
C++ 代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l,r;
bool operator< (const Range&W)const
{
return l < W.l;
}
}range[N]; //重载小于号,使其以左端点进行排序
int main()
{
int n;
cin >> n;
for(int i = 0;i < n;i ++)
{
int l,r;
scanf("%d%d",&l,&r);
range[i] = {l,r};
}
sort(range,range + n);
int res = 1;
int maxr = range[0].r;
for(int i = 1;i < n;i ++)
{
if(range[i].l <= maxr) maxr = max(maxr,range[i].r);
else
{
res ++;
maxr = range[i].r;
}
}
cout << res << endl;
return 0;
}
算法二
贪心以右端点排序再次水过
思路:
思路与上一种差不多,不过右端点需要从右到左来合并区间
C++代码
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l,r;
bool operator< (const Range&W)const
{
return r < W.r;
}
}range[N];
int main()
{
int n;
cin >> n;
for(int i = 0;i < n;i ++)
{
int l,r;
scanf("%d%d",&l,&r);
range[i] = {l,r};
}
sort(range,range + n);
int res = 1;
int maxl = range[n - 1].l;
for(int i = n - 2;i >= 0;i --)
{
if(range[i].r >= maxl) maxl = min(maxl,range[i].l);
else
{
res ++;
maxl = range[i].l;
}
}
cout << res << endl;
return 0;
}
算法二
区间合并正常思路(y总解法)
思路:
非原创所以不配写思路
C++代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
vector<PII> segs;
void merge(vector<PII>&segs)
{
vector<PII> res;
sort(segs.begin(),segs.end());
int l = -2e9,r = -2e9;
for(auto item:segs)
if(r < item.first)
{
if(l != -2e9) res.push_back({l,r});
l = item.first;
r = item.second;
}
else r = max(r,item.second);
if(l != -2e9) res.push_back({l,r});
segs = res;
}
int main()
{
int n;
cin >> n;
while(n--)
{
int l,r;
scanf("%d%d",&l,&r);
segs.push_back({l,r});
}
merge(segs);
cout << segs.size() << endl;
return 0;
}
ps
三种解法时间复杂度差不多,此处就不一一分析,感谢大家观看菜逼写的。。
一言一语都再说:
$y总这么牛逼,竟然用了这么复杂的写法来写!$
确实hh
说实话,感觉确实写复杂了,y总的写法不仅求了个数,还求了合并区间
不过这代码就算改一下题目求合并区间也是可以过的…
要是再求一个 离散化 前缀求和呢 感觉还是把区间都弄出来好
if(l != -2e9) res.push_back({l,r});这里的if(l != -2e9)难道不多于吗,只要n>=1,l就不可能是-2e9
还是不太清楚没有-2e9会导致什么问题有人能解答一下吗 这个初始化int l = -2e9,r = -2e9;跟这个判断条件if(l != -2e9)
真不错
if(l != -2e9) res.push_back({l,r});请问这句是什么意思呀?什么情况下遍历完l还会等于-2e9呢?
就是初始区间-2e9到-2e9 这个区间是严格小于第一个segs的左端点的但不能把它放进res里
想问一下第二条这个语句怎么理解
当整个容器只有一个数值的时候,l和r被更新了一次但是放不进去,需要在最后补充
右端点排序为什么要倒着遍历啊,求大佬解答一下
顺着也行。
顺着不行,只按照右端点排序如果右端点都相等排序是随机的会出现下面这种情况
-10 20
30 40
10 40
贪心和y总写的不一样吗?只是一个是结构体,一个是pair结构吧。
感谢菜逼观看哈哈
学完贪心再来补思路吧
第一种方法的重载运算符不是画蛇添足吗。。。
sort结构体,这不就用上了吗。。。
两个元素,可以用用PII啊,就不用重载运算符了
对,你聪明,你聪明,买不到了
if(l != -2e9) res.push_back({l,r});
这行代码如何理解?
因为可能只剩一个区间,其他都输出了,不用比较直接输出就行
tql,插个眼,后续学完贪心再回来理解思路
hhh
牛啊
妙啊
只是求合并后的区间个数的话其实还是很好求的,但是y总的方法把合并后的区间也写了出来
前俩种也可以求合并后的区间
是的
求细说。
需要开新的空间吗
不需要吧
靠,右排竟然是倒着比的,%%%%%%
肯定呀!!!