合并区间、插入区间~
56. 合并区间 - 力扣(LeetCode)
首先是合并区间,这道题是ACwing的模板题,其实我有点想不通为什么要把一道模拟题做成模板,直到今年科软机试考了这道题,感觉这道题确实是面试和机试的高频考点:
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(),intervals.end());
int start = -2e9;
int end = -2e9;
vector<vector<int>> res;
for(auto interval : intervals){
int newstart = interval[0];
int newend = interval[1];
if(newstart > end){
if(start != -2e9) res.push_back({start,end});
start = newstart; end = newend;
}else{
end = max(end , newend);
}
}
if(start != -2e9) res.push_back({start,end});
return res;
}
};
我这里也是直接背模板,首先我们要sort一下(听说科软机试是纯c,没有内置sort函数。。)然后声明start和end为非常小的值,其实也是把[start,end]当作第一个区间,然后开始遍历每一个新区间,这里就分两种大情况:
一种是新区间的左端点要大于上一个区间的右端点,就没有交集。这时候判断一下,如果start不是当初那个极小值就把维护的这一段区间加入到结果中,然后转而去用start和end维护新区间。
另一种是新区间的左端点小于上一个区间的右端点,这时就有了交集,让end=max(end,newend)实际上还包括了两种小情况。没有接触过这道题的读者可以想一想是哪两种小情况。
最后遍历结束后,别忘了把最后一个维护的区间加入。
因为他每回插入答案的都是上一个维护的区间,所以导致在最后维护的新区间不会插入到结果中。
57. 插入区间 - 力扣(LeetCode)
这里有一个非常偷懒的做法:就是直接copy上一题的代码,然后把新区间插入到区间集合里面进行区间合并,而且由于本来就是有序的,所以sort一下好像不会花太多时间。但是这样就没有利用到有序的特性。
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
intervals.push_back(newInterval);
sort(intervals.begin(),intervals.end());
int start = -2e9;
int end = -2e9;
vector<vector<int>> res;
for(auto interval : intervals){
int newstart = interval[0];
int newend = interval[1];
if(newstart > end){
if(start != -2e9) res.push_back({start,end});
start = newstart; end = newend;
}else{
end = max(end , newend);
}
}
if(start != -2e9) res.push_back({start,end});
return res;
}
};
更好的做法是这一种:
但是这种模拟题需要思维逻辑特别清晰,我不一定能想到
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
int left = newInterval[0];
int right = newInterval[1];
bool placed = false;
vector<vector<int>> ans;
for (const auto& interval: intervals) {
if (interval[0] > right) {
// 在插入区间的右侧且无交集
if (!placed) {
ans.push_back({left, right});
placed = true;
}
ans.push_back(interval);
}
else if (interval[1] < left) {
// 在插入区间的左侧且无交集
ans.push_back(interval);
}
else {
// 与插入区间有交集,计算它们的并集
left = min(left, interval[0]);
right = max(right, interval[1]);
}
}
if (!placed) {
ans.push_back({left, right});
}
return ans;
}
};
这个placed标记新区间是否被插入。大伙看一下注释吧。
1.如果当前遍历的区间的右端点在新区间左端点左边,就没有交集。
2.发现第一个满足区间左端点大于新区间右端点的区间,如果新区间没插入就把left和right维护的中间一大坨插入,再插入这个区间。
3.其他情况就是有交集,计算并集维护这一坨区间。
在遍历结束后,特判新区间有没有插入,如果没有的话说明新区间足够大把后面的区间全部覆盖了。所以最后我们插入维护的区间结束。