携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
题目描述
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
来源:力扣(LeetCode) 链接:leetcode.cn/problems/me…
示例 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
解题思路
首先我们来理解一下题意。
不重叠的情况
假设有两个区间 [0,5] 和 [6,8],相当于 [0,1,2,3,4,5] 和 [6,7,8],可以看出它们两个是没有交集的。因此两个区间的不重叠区间数组为 [0,1,2,3,4,5,6,7,8],也就是[0,5] 和 [6,8]。
对于不重叠的情况来说,我们需要返回的数组应该是[区间1, 区间2]。
全部重叠的情况
假设有两个区间 [0,5] 和 [1,3],相当于 [0,1,2,3,4,5],两个区间的交集就是[1,2,3],也就是说[1,3] 是被 [0,5] 全包含的,最终它们的不重叠区间数组为 [0,1,2,3,4,5],也就是[0,5]。
对于全部重叠的情况来说,我们需要返回的数组应该是[表示范围更广的那个区间]。
部分重叠的情况
假设有两个区间 [0,5] 和 [2,7],相当于 [0,1,2,3,4,5,6,7],它们的交集是 [2,3,4,5],但是区间2的结尾是比区间1多了 [6,7],是更广的一个范围,所以他们的不重叠区间数组应该是 [0,1,2,3,4,5,6,7],也就是[0,7]。
对于部分重叠情况来说,我们需要返回的数组应该是[起始更早的区间的start,结束更晚的区间的end]。
有了这三部分的逻辑,我们就可以开始着手解题了。
题解
为了使得计算方便,我们可以对所有区间的start进行从小到大的排序,这样做的好处:
① 另一个区间的 start 是否大于当前区间的 end,如果是,则说明是两个不重叠的区间。
② 另一个区间的 start 小于当前区间的end,那么它可能是全部重叠,也可能是部分重叠。如果另一个区间的end也小于当前区间的end的话,则说明另一个区间和当前的区间全部重叠,否则就说明是部分重叠。
我们根据这个逻辑就可以写出相应的程序了。
/**
* @param {number[][]} intervals
* @return {number[][]}
*/
var merge = function(intervals) {
intervals = intervals.sort((a, b)=>a[0]-b[0]);
return intervals.reduce((f, c) => {
const lens = f.length-1, last = f[lens];
if(!last) {
return [c]; // 首个区间必然是直接作为结果数组的其中一个元素了
}
if(c[0] > last[1]) { // 如果当前区间的 start 大于先前区间的end,则说明不重叠,直接push
f.push(c);
} else if(c[1] > last[1]) {
// 否则就是部分重叠,取[起始更早的区间的start,结束更晚的区间的end]
f[lens] = [last[0], c[1]];
}
return f;
}, []);
};