区间合并及模板

区间合并及模板

1. 区间合并的应用

img

    假设,我们拥有很多区间,我们需要将有交集的区间合并成为一个区间。类似于这样的问题就叫做区间合并问题。请看上图:
    区间合并算法就是要尽可能快的完成上述操作。

img

    区间合并算法有时会需要处理一下边界问题,这种情况需要具体问题具体分析。边界问题指的就是当两个区间只有端点重合时,是否要进行合并?

img

    下面通过例题中的案例来辅助理解。(注:这里考虑了边界问题)

img
img
img

    如何进行区间合并?步骤如下:
        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/

img

    例题按照上述算法的模拟如上图所示:
    过程如下:
        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。其余内容均为作者原创。
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @   夏目^_^  阅读(146)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示