一些关于区间的力扣题目
- 228. 汇总区间
- 56. 合并区间
- 57. 插入区间
228. 汇总区间
题目链接:228.汇总区间
题目内容:
看题目真是没懂这个题到底是要干啥……实际上题目要求的恰好覆盖数组中所有数字的最小有序区间范围列表,这个最小是指一个区间范围小。比如能够覆盖{2,3,4,6}的区间可以是[2,6],但是5在区间内,却不在数组内,因此这个区间不是最小的,可以缩小成[2,4]和[6,6],这才是满足题意恰好覆盖所有数字的最小区间。
理解题意后,解法就很简单了,为了保证区间能够覆盖所有数组中的数字,同时又不存在在区间内但不在数组内的数字,那就只能考虑用数组内的连续数字来组成区间。什么意思呢?就是把数组内连续的数字组成一个区间,单独的数字单独一个区间。比如上面的{2,3,4,6},其中{2,3,4}就是连续的,组成一个区间[2,4],6是单独的需要一个区间[6, 6]。由于数组本身是有序的,那么就找连续递增的数字组成一个区间,nums[j] == nums[j-1]。 代码如下(C++):
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> ans;
int start = 0, end = 1;
while(end <= nums.size()){
//end是连续区间结束后的数字
if(end == nums.size() || nums[end] != nums[end - 1] + 1){
if(start == end - 1)
//如果start和end-1相等,说明这是只有一个数字的独立区间
ans.emplace_back(to_string(nums[start]));
else
//start到end-1是连续区间
ans.emplace_back(to_string(nums[start])+"->"+to_string(nums[end-1]));
start = end; //下一段区间的开始
}
end++;
}
return ans;
}
};
56. 合并区间
题目链接:56. 合并区间
题目内容:
先看看给的例子,理解题意:
题目要求我们合并重叠的区间,那什么算是重叠的区间呢?在区间是按照左端点升序排序的前提下,前面一个区间d1的右端点与后面一个区间d2的左端点有交集,即d1.right ≥ d2.left,就说明两个区间重叠,至于d2.right与d1.right的大小关系,是不重要的:
d1和d2有交集,将两个区间合并成[ min(d1.left,d2.left),max(d1.right,d2.right) ]。
所以首先要做的是将区间数组按照区间的左端点排序,之后开始判断前后两个区间是否有重叠。判断是否重叠只需要将答案区间数组中最后一个区间和待加入的区间比较,因为当前答案数组的最后一个区间的left是比待加入的区间left更小的,答案区间数组中的区间是没有重叠的,那么答案数组中的最后一个区间的left肯定是大于再前面一个区间的right的,待加入区间的left肯定是比答案数组中倒数第二个区间的right更大的。代码如下(C++):
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if(intervals.size() == 0)
return intervals;
sort(intervals.begin(), intervals.end()); //排序,左端点升序
vector<vector<int>> ans; //最终无重叠的区间数组
for(int i = 0; i < intervals.size(); i++){
//对于第一个区间和不重叠的区间,直接加入
if(ans.size() ==0 || ans.back()[1] < intervals[i][0])
ans.emplace_back(intervals[i]);
else
//有重叠的区间,最后一个区间的right要修改为两个重叠区间更大的right
ans.back()[1] = max(intervals[i][1], ans.back()[1]);
}
return ans;
}
};
57. 插入区间
题目链接:57. 插入区间
题目内容:
这道题其实和上一题是差不多的。给的区间已经按照左端点排序好了,先查找到待插入的区间应该插入的位置,然后插入再合并重叠的区间即可。如果一个区间d.right < newin.left的话,很显然这个区间d是和newin是不重叠的,在其左边;如果一个区间d.left > newin.right的话,很显然这个区间d在其右边,是不重叠的。除上述两种情况外,那就是有重叠的部分,和一个区间重叠后,合并的区间left = min(newin.left,d.left),只有第一个开始重叠的地方需要更新left,之后right = max(newin.right,d.right)。以下例举了部分情况:
实际上还有在最前面、最后面插入的情况,不需要额外讨论,一样按照上述三种情况去判断就好了,最前面和最后面只是插入的位置和重叠位置有些特殊。实现代码如下(C++):
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
vector<vector<int>> ans;
int idx = 0;
//先把在插入区间左边的区间直接加入答案数组中
while(idx < intervals.size() && intervals[idx][1] < newInterval[0]){
ans.emplace_back(intervals[idx]);
idx++;
}
//如果已经在最后了或者是空的,直接插入
if(idx == intervals.size()) {
ans.emplace_back(newInterval);
return ans;
}
//否则idx对应的区间和待插入区间是有重叠的,更新left
else{
newInterval[0] = min(intervals[idx][0], newInterval[0]);
}
//开始查找重叠部分,直到找到在待插入区间右边的区间
while(idx < intervals.size() && intervals[idx][0] <= newInterval[1]){
//有重叠就更新right
newInterval[1] = max(intervals[idx][1], newInterval[1]);
idx++;
}
//插入区间
ans.emplace_back(newInterval);
//之后的区间全在待插入区间的右边,直接加入
while(idx < intervals.size())
ans.emplace_back(intervals[idx++]);
return ans;
}
};