跳到主要内容

6 - 区间合并

准备春招,算法题冲冲冲!

区间合并

区间合并,就是将所有存在 交集 的区间进行一个合并。如图,五个蓝色的区间可以合并成三个绿色的区间:

image-20220704214742972

PS:若两个区间只有端点是相交的,这两个区间也能合并。

思路

  1. 按区间左端点排序。
  2. 扫描整个区间,把所有可能有交集的区间进行合并。

例如,当前所维护的区间如图:

image-20220704215104664

可能有交集的区间如下:

  • 在维护区间的内部,我们不做处理:

    image-20220704215438464

  • 有交集(右侧突出),延长ed到突出的位置:

    image-20220704215603358

  • 无交集,说明当前区间已经维护完毕,开始维护这个新区间:

    image-20220704215505516

代码

参考代码如下:

void merge(vector<pair<int, int>>& segs)
{
vector<pair<int, int>> res;
// 1.先对区间进行排序
sort(segs.begin(), segs.end());
// 2.开始区间合并
int st = -2e9, ed = -2e9; // 按题目范围自定义
for (auto seg : segs)
{
// 情况3: 找到新区间
if (ed < seg.first)
{
// 存储维护好的区间(最开始的除外)
if (ed != -2e9)
{
res.push_back({st, ed});
}
// 开始维护新区间
st = seg.first;
ed = seg.second;
}
else
{
// 情况2: 有交集, 右侧突出
ed = max(ed, seg.second);
}
}
// 存储维护好的区间(最开始的除外)
if (st != -2e9)
{
res.push_back({st, ed});
}

segs = res;
}

例题

803. 区间合并 - AcWing题库

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

using PII = pair<int, int>;

void merge(vector<PII>& segs)
{
vector<PII> ans;

// 1. 排序区间
sort(segs.begin(), segs.end());

// 2. 进行区间合并
int st = -2e9, ed = -2e9;
for (auto [start, end] : segs)
{
// 情况3
if (ed < start)
{
if (st != -2e9)
ans.emplace_back(st, ed);
st = start;
ed = end;
}
else
{
// 情况2
ed = max(ed, end);
}
}

if (st != -2e9)
ans.emplace_back(st, ed);

segs = ans;
}

int main()
{
int n, l, r;
cin >> n;

vector<PII> segs;
segs.reserve(n);
for (int i = 0; i < n; ++i)
{
cin >> l >> r;
segs.emplace_back(l, r);
}

merge(segs);

cout << segs.size();
}

56. 合并区间 - 力扣(LeetCode)

模板题

vector<vector<int>> merge(vector<vector<int>>& intervals) {
int st = -1, ed = -1;
vector<vector<int>> ans;
ans.reserve(intervals.size());

sort(intervals.begin(), intervals.end());
for (auto& seg : intervals)
{
if (seg.at(0) > ed)
{
if (ed != -1)
{
ans.emplace_back(vector<int>({st, ed}));
}
st = seg.at(0);
ed = seg.at(1);
}
else
{
ed = max(seg.at(1), ed);
}
}

if (ed != -1)
{
ans.emplace_back(vector<int>({st, ed}));
}

return ans;
}

参考资料