56. 合并区间
难度中等1214
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
1.c++
/*
* 2021-12-5 22:15
* Hangzhou
*
*/
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
class Solution {
public:
bool merge2vec(vector<int>& vec1,vector<int>& vec2)
{
if (vec2[0] > vec1[1])
{
return false;
}
else if (vec2[0] <= vec1[1] && vec2[1] > vec1[1])
{
vec2[0] = vec1[0];
return true;
}
else if (vec1[0] >= vec2[0] && vec1[1] >= vec2[1])
{
vec2[0] = vec1[0];
vec2[1] = vec1[1];
return true;
}
return false;
}
vector<vector<int>> merge(vector<vector<int>>& intervals)
{
vector<vector<int>> ret;
//将各区间按照边界(第一个元素)从小到大排序
std::sort(intervals.begin(),intervals.end(),[](std::vector<int> &pre,std::vector<int> &next)->bool
{
return pre[0] < next[0];
});
int size = intervals.size();
//将排序后的区间从左到右进行合并
bool bad_vec[size] = {false};
int i = 0;
while (i < size - 1)
{
auto &first_vec = intervals[i];
auto &second_vec = intervals[i+1];
if (true == merge2vec(first_vec,second_vec))
{
bad_vec[i] = true;
}
++i;
}
for (int i = 0; i < size;++i)
{
if (bad_vec[i] == false)
{
ret.push_back(intervals[i]);
}
}
return ret;
}
};
template<class T>
void print_sequence(T &container)
{
for (auto &elem:container)
{
for (auto &e:elem)
{
std::cout<<e << std::endl;
}
std::cout<<"--------------"<<std::endl;
}
}
int main()
{
Solution slu;
std::vector<std::vector<int>> vec_2 = {{1,3},{2,6},{8,10},{15,18}};
auto ret = slu.merge(vec_2);
print_sequence(ret);
return 0;
}
2.思路讲解:
(1) 区间合并的标准是区间存在交集或包含关系,为了更好地找到各个区间的交集关系,所以我们先将各区间按照其start边界从小到大地排序。
如原始输入:
intervals = [[1,3],[15,18],[8,10],[2,6]]
按照区间的start排序后变为:
intervals = [[1,3],[2,6],[8,10],[15,18]]
(2) 排序后,相邻两区间的关系就只可能是如下三种:
这就是我们在使用函数bool merge2vec(vector<int>& vec1,vector<int>& vec2)
合并区间vec1、vec2时它俩之间可能的关系。
于是我们在不同的情况分支进行合并((1)、(2)、(3)), 此时,只有条件(2)、(3)这两种情况需要合并。
(3)关键点:
a) 为了能够在一趟扫描(O(n)) 的过程中就能合并所有的区间,如果相邻区间A、B需要合并,那么我们通过修改B的边界值,将其变为合并后的新区间,这样在++i后就可以合理且正确进行下一次的相邻区间B、C的合并。
b) 当相邻区间A、B合并且置B区间为新区间后,后续从当前的区间组合中返回最终的结果。A区间就应该不再采用,所以在发生合并后我们应该将A区间置为废弃。
if (true == merge2vec(first_vec,second_vec))//发生合并
{
bad_vec[i] = true;
}
(4)在完成合并过程后,返回新的区间组合。
即从intervals区间组合中,将那些未被标记为废弃的区间取出来插入到新区间,返回。
for (int i = 0; i < size;++i)
{
if (bad_vec[i] == false)
{
ret.push_back(intervals[i]);
}
}