题目链接
题目描述
以数组 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
解题思路
排序
如果我们按照区间的左端点排序,那么在排完序的列表中,可以合并的区间一定是连续的。如下图所示,标记为蓝色、黄色和绿色的区间分别可以合并成一个大区间,它们在排完序的列表中是连续的:
我们用数组 res 存储最终的答案。
首先,我们将列表中的区间按照左端点升序排序。然后我们将第一个区间加入 res 数组中,并按顺序依次考虑之后的每个区间:
- 如果当前区间的左端点在数组 res 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 res 的末尾;
- 否则,它们重合,我们需要用当前区间的右端点更新数组 res 中最后一个区间的右端点,将其置为二者的较大值。
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
int len = intervals.size();
if(len<2)
return intervals;
sort(intervals.begin(),intervals.end());
vector<vector<int>> res;
for(int i=0;i<len;++i){
int L = intervals[i][0],R = intervals[i][1];
if(!res.size()||res.back()[1]<L){
res.push_back({L,R});
}else{
res.back()[1] = max(res.back()[1],R);
}
}
return res;
}
};
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
int len = intervals.size();
if(len<=1){
return intervals;
}
vector<vector<int>> ans;
sort(intervals.begin(),intervals.end(),[](vector<int>&a,vector<int>&b){
return a[0]<b[0];
});
int l = intervals[0][0],r = intervals[0][1];
for(int i=1;i<len;i++){
// 如果没有重合
if(intervals[i][0]>r){
ans.push_back({l,r});
l = intervals[i][0];
r = intervals[i][1]; // 如果有重合并且r大于之前
}else if(intervals[i][1]>r){
r = intervals[i][1];
}
}
// 将最后一个加入结果
ans.push_back({l,r});
return ans;
}
};
// List版
class Solution {
public int[][] merge(int[][] intervals) {
if(intervals.length < 2){
return intervals;
}
Arrays.sort(intervals, new Comparator<int[]>() {
public int compare(int[] a, int[] b){
return a[0] - b[0];
}
});
// lambda表达式
// Arrays.sort(intervals, (a1, a2) -> a1[0] - a2[0]);
List<int[]> res = new LinkedList<int[]>();
for(int i = 0; i < intervals.length; ++i){
int L = intervals[i][0], R = intervals[i][1];
if(res.size() == 0 || res.get(res.size() - 1)[1] < L){
res.add(new int[]{L, R});
}else{
res.get(res.size() - 1)[1] = Math.max(res.get(res.size() - 1)[1], R);
}
}
return res.toArray(new int[res.size()][]);
}
}
// 数组版
class Solution {
public int[][] merge(int[][] intervals) {
if(intervals.length < 2){
return intervals;
}
// 排序,先按左边界从小到大排, 再按右边界从小到大排
Arrays.sort(intervals, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
// pos标记当前合并后的位置,即合并到第几个区间
int pos = 0;
// i标记当前合并的位置,即遍历到第几个区间
for(int i = 1; i < intervals.length; ++i){
// 如果当前遍历到的区间左边界在前面区间中,进行合并
if(intervals[i][0] <= intervals[pos][1]){
intervals[pos][1] = Math.max(intervals[pos][1], intervals[i][1]);
}else{
// 开始新的区间合并
++pos;
intervals[pos][0] = intervals[i][0];
intervals[pos][1] = intervals[i][1];
}
}
// 将数据返回
int[][] res = new int[pos + 1][2];
for(int i = 0; i <= pos; ++i){
res[i][0] = intervals[i][0];
res[i][1] = intervals[i][1];
}
return res;
}
}
- 时间复杂度 O(nlogn)
- 空间复杂度 O(logn)