区间合并及模板
区间合并及模板
1. 区间合并的应用
假设,我们拥有很多区间,我们需要将有交集的区间合并成为一个区间。类似于这样的问题就叫做区间合并问题。请看上图:
区间合并算法就是要尽可能快的完成上述操作。
区间合并算法有时会需要处理一下边界问题,这种情况需要具体问题具体分析。边界问题指的就是当两个区间只有端点重合时,是否要进行合并?
下面通过例题中的案例来辅助理解。(注:这里考虑了边界问题)
如何进行区间合并?步骤如下:
1. 按照区间的左端点排序(从小到大)。
2. 排序之后,依次从左到右扫描所有区间,并维护一个当前区间S。
3. 根据当前区间和下一个区间的位置,我们可以分为三种情况:
1. 如果下一个区间处于当前区间内(下一个区间的左右端点均处于当前区间内),那么代表有交集,保持当前区间不变即可,对应上面的第一张图。
2. 如果下一个区间跟当前区间有重合,但并不都包含在当前区间中,(下一个区间的左端点处于当前区间内,但右端点不是)那么将当前区间的右端点进行更新,使其延长成更长的区间,对应上面的第二张图。
3. 如果下一个区间的左端点并不在当前区间中,代表下一个及之后的所有区间跟当前区间均无交集,那么将合并后的区间个数加一,将下一个区间作为当前区间,继续扫描即可。对应上面的第三张图。
根据上述的步骤,我们发现区间合并具有如下性质:由于我们已经按照左端点进行从小到大排序,并且也按照从左到右来进行扫描区间。那么我们可以确定:下一个区间的左端点绝不可能在当前区间的左边。即:如果当前区间和下一个区间没有交集的话,下一个区间绝不可能出现在当前区间的左侧。并且也可以保证的是:下一个区间之后的所有区间均与当前区间没有交集。
2.区间合并模板
// 将所有存在交集的区间合并
// 这里的PII代表pair数对
void merge(vector<PII> &segs)
{
vector<PII> res;
sort(segs.begin(), segs.end());
//st和ed代表当前维护区间的左右端点
//当前维护区间最开始初始化为:负无穷,负无穷
//代表没有遍历任何一个区间
int st = -2e9, ed = -2e9;
for (auto 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);
//这里是为了防止segs为空的情况
if (st != -2e9) res.push_back({st, ed});
segs = res;
}
3.区间合并例题
https://www.acwing.com/problem/content/805/
例题按照上述算法的模拟如上图所示:
过程如下:
1. 当第一个区间作为当前区间,查看第二个区间发现有交集,将当前区间的右端点进行延长,并保持当前区间不变。
2. 再扫描下一个区间,发现下一个区间与当前区间没有交集,那么可以保证下一个区间及之后的所有区间均与当前区间没有交集。那么将合并的区间数+1,将下一个区间作为当前区间。
3. 扫描下一个区间(从图中可以看到下两个区间的左端点都是一样的,这时我们可以选取这两个区间的任意一个作为下一个区间,在这里我们选择7和8这个区间)发现与当前区间没有交集,因此将合并的区间数+1,将下一个区间作为当前区间。
4. 扫描下一个区间,发现有交集,因此将当前区间的右端点进行延长,并保持当前区间不变。
5. 至此,已经扫描完所有区间了。因此,将合并的区间数+1即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
void merge(vector<pair<int,int>> &segs){
vector<pair<int,int>> res;
sort(segs.begin(),segs.end());
int st = -2e9,ed = -2e9;
for(auto 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);
}
}
if(st != -2e9){
res.push_back({st,ed});
}
segs = res;
}
int main(){
int n;
int l,r;
scanf("%d",&n);
vector<pair<int,int>> segs;
for(int i=0;i<n;i++){
scanf("%d %d",&l,&r);
segs.push_back({l,r});
}
//进行合并
merge(segs);
//输出
printf("%d",segs.size());
return 0;
}
作者:gao79138
链接:https://www.acwing.com/
来源:本博客中的截图、代码模板及题目地址均来自于Acwing。其余内容均为作者原创。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!