给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1:
输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]
示例 2:
输入: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]]
解释: 这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。
解析:本题是基于上一题的修改版,因此提供两种解决方法,第一种是在上一题的基础上修改,第二种是不基于上一题的新思路。
第一种,在上一题的基础上修改。上一题提供的起始集合便是未排序,包含重叠区间的给定容器。而本题是要求将给定区间插入原集合中。最简单的办法便是将区间直接加入原集合,然后交付由上一题的函数计算便可。
如何减少时间,上一题的许多时间消耗在了给集合排序上,我们可以利用原集合有序的特点,使用二分法手动插入新区间。
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
int l = 0;
int r = intervals.size();
int m;
while(l<r){
m = l + (r-l)/2;
if(intervals[m][0]<newInterval[0]) l=m+1;
else if(intervals[m][0]>newInterval[0]) r=m;
else{
if(intervals[m][1]<newInterval[1]) l=m+1;
else if(intervals[m][1]>newInterval[1]) r=m;
else return intervals;
}
}
intervals.insert(intervals.begin()+l,newInterval);
//以下是上一题的部分
int n = intervals.size();
vector<int> starts, ends;
for (int i = 0; i < n; ++i) {
starts.push_back(intervals[i][0]);
ends.push_back(intervals[i][1]);
}
vector<vector<int>> res;
sort(ends.begin(),ends.end());
for (int i = 0, j = 0; i < n; ++i) {
if (i == n - 1 || starts[i + 1] > ends[i]) {
res.push_back({starts[j], ends[i]});
j = i + 1;
}
}
return res;
}
};
第二种方法,即忽略上一题的结果,重新编程。
很容易将原区间分成三部分,一是完全小于新区间的区间,二是与新区间有重叠部分的区间,三是完全大于新区间的区间。对于一和三两部分,我们可以不予理会,直接将其准备输出。那么我们只需要将第二部分的区间进行合并即可。
定义索引n,遍历整个集合,对于第一部分和第三部分,将其插入待输出结果。
对于第二部分的区间,利用其数值更新新区间的数组,最后将新区间插入待输出结果。
整个过程不再需要排序,也不需要新的额外空间,时间复杂度O(N),空间复杂度O(1)
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
vector<vector<int>> res;
if(intervals.size()==0) return res.push_back(newInterval),res;
int n = 0;
//所有小于新区间的区间
while(n<intervals.size()){
//如果结束点小于新区间起始点
if(intervals[n][1]<newInterval[0]){
res.push_back(intervals[n++]);
}
else break;
}
//计算并插入合并后的区间
while(n<intervals.size()){
//如果起始点小于等于新区间结束点,即需要合并
if(newInterval[1]>=intervals[n][0]){
//如果起始点小于新区间起始点
if(intervals[n][0]<newInterval[0]){
newInterval[0]=intervals[n][0];
}
//如果结束点大于新区间结束点
if(intervals[n][1]>newInterval[1]){
newInterval[1]=intervals[n][1];
}
++n;
}
else break;
}
res.push_back(newInterval);
//剩下的区间
while(n<intervals.size()){
res.push_back(intervals[n++]);
}
return res;
}
};