看完这题题目
还记得小时候很常被问到:
给你一些数字,请你从这些数中用最少的数,来涵盖最多的范围。於是我们就会拿起笔开画数线。不过今天,我们要用程序码来解题,没有了画笔,我们该如何下手?
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
在解题之前我们先想想要如何在阵列中长得像这样[starti, endi]的元素。只依靠start和end,来决定是否有区间重叠,毕竟我们从画图很容易可以看得出来哪些元素共享哪几个重叠的数,但如果现在我只告诉你头尾两个数,我们是不是需要去比较区间才能知道?
这里我们随意抓出第一和第二个元素也就是[1,3
]和[2
,6]
我们可以推断:如果第一个元素的 end ≥ 第二个元素的start (3 ≥ 2),就代表有重叠发生
但如果今天的范例长成 intervals = [[8,10],[2,6],[1,3],[15,18]]
我们一样抓出第一和第二个元素也就是 [8,10],[2,6]
依照前面的推断,因为 10 ≥ 6,所以有重叠!? 完蛋!
也就是说,我们先前可以轻松地抓两个元素来比较是因为:前面的范例恰好每个元素的start是由小到大排列的
,也就是说我们应该要确保,每个元素的排列是依照前面的元素大小来排列。
接着再思考一个问题,我们要如何合并多个有重叠的元素,像是我们在原本的范例再多塞一个变成
intervals = [[1,3],[2,6],[5,7],[8,10],[15,18]]
我们应该要把 [1,3],[2,6],[5,7] 合并成 [1,7]
我们可以先把[1,3] 和 [2,6]合并成 [1,6]後,再用[1,6]和[5,7]下去做合并变成[1,7]。
但我们要如何产出[[1,7],[8,10],[15,18]]这个答案?
我们是不是在过程中有一个[1,6]消失了?
也就是说假设我们有一个暂存区空阵列[],我们把[[1,6]]加入後,往下走到[5,7],我们应该要拿[5,7]去和暂存区内的[1,6]确认
,看看他们有没有需要合并,如果下个元素的start≤前一个暂存区的end,就代表有合并的动作要做。
我们取暂存区的end(6)和下个元素的end(7),`取大的当作end`,直接可以把暂存区这个元素的end替换掉,产生了[1,7]!
那为什麽我们要取大的元素当end,而不直接取後面的?
因为有可能会有[[1,7],[3,6]]这种被涵盖的情况发生。
总结我们要做的事
前面元素的 end ≥ 後面元素的start
,如果有则要做合并,改变end的操作以上的做法,时间复杂度为O(nlogn)→主要花在排序,空间复杂度O(n) → 我们的ouput,因为最糟为都没有重叠
最後就是实作程序码。
希望看完上面的解释,希望你也觉得这题根本就跟画数线一样简单拉!
var merge = function (intervals) {
const sortIntervals = intervals.sort((a, b) => a[0] - b[0]);
const output = [];
let current = sortIntervals[0];
output.push(current);
for (const next of sortIntervals) {
const [currentStart, currentEnd] = current;
const [nextStart, nextEnd] = next;
if (currentEnd >= nextStart) current[1] = Math.max(currentEnd, nextEnd);
else {
current = next;
output.push(current);
}
}
return output;
};
明日题目预告:Maximum Subarray
1. 标题标签 <h1> - <h6> (一级标题 - 六级标题) 文字粗体...
我们上篇有讲到判断式有两种语法,这次要说到的就是switch这个语法了。 这个语法适合用在多重判断上...
今天要结合前两天的成果,完成 LIFF APP 串接 发送认证码 API 的功能 目标 要完成的功能...
本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...
在 React中处理事件就像 HTML 一样,React 可以根据用户事件执行动作。 具有与 HTM...