一、题目描述
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
css
输入: intervals = [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
lua
输入: intervals = [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
二、题解
本人错误题解
js
var merge = function(intervals) {
let ansSet=new Set();
let ans=[];
let left=0;
let right=0;
if(intervals.length===0){
return [];
}
if(intervals.length===1){
return intervals;
}
for(let i=0;i<intervals.length;i++){
for(let j=intervals[i][0];j<=intervals[i][1];j++){
ansSet.add(j);
}
}
const ansArray = Array.from(ansSet);
ansArray.sort((a, b) => a - b);
while(right<ansArray.length&&left<ansArray.length){
if(ansArray[right]===ansArray[right+1]-1){
right++;
}else{
ans.push([ansArray[left],ansArray[right]])
left=right+1;
right++;
}
}
return ans;
};
错误之处现在于没有考虑到区间里面的数据是连续的
正确题解
js
/**
* @param {number[][]} intervals
* @return {number[][]}
*/
var merge = function(intervals) {
if (!intervals || intervals.length === 0) {
return []; // 处理空数组的情况
}
// 1. 按照起始位置升序排序
intervals.sort((a, b) => a[0] - b[0]);
const merged = []; // 用于存储合并后的区间
let currentInterval = intervals[0]; // 初始化当前区间
for (let i = 1; i < intervals.length; i++) {
const nextInterval = intervals[i];
// 2. 判断是否重叠:nextInterval[0] <= currentInterval[1]
if (nextInterval[0] <= currentInterval[1]) {
// 3. 如果重叠,合并区间,选择更大的结束位置
currentInterval[1] = Math.max(currentInterval[1], nextInterval[1]);
} else {
// 4. 如果不重叠,将当前合并好的区间推入结果数组,并更新当前区间
merged.push(currentInterval);
currentInterval = nextInterval;
}
}
merged.push(currentInterval); // 5. 添加最后一个合并后的区间
return merged;
};
核心思想
此题的核心思想是使用贪心算法,具体来说,就是通过排序和迭代来逐步地合并重叠的区间。贪心策略在于:每次都尽可能地合并当前区间,直到遇到不重叠的区间为止。
详细题解
-
处理边界情况:
- 当输入数组
intervals
为空或null
时,函数立即返回空数组[]
。 这是一个良好的编程习惯,避免了可能的空指针或空数组访问错误。
- 当输入数组
-
排序:
- 使用
intervals.sort((a, b) => a[0] - b[0])
按区间的起始位置升序排序。 这至关重要,因为排好序后,所有可能重叠的区间都会在数组中相邻。 排序是确保贪心策略能正确实施的关键。
- 使用
-
初始化:
merged
数组用于存储合并后的不重叠区间。currentInterval
变量指向当前正在构建的合并区间,初始值为排序后的第一个区间intervals[0]
。
-
迭代和合并:
-
循环遍历排序后的
intervals
数组(从第二个区间开始)。 -
对于每个
nextInterval
,检查它是否与currentInterval
重叠:- 如果重叠: 如果
nextInterval[0] <= currentInterval[1]
,则表示nextInterval
与currentInterval
重叠。此时,需要更新currentInterval
的结束位置,即currentInterval[1] = Math.max(currentInterval[1], nextInterval[1])
。这样做可以确保currentInterval
能够包含所有重叠区间的范围。 - 如果不重叠: 如果
nextInterval[0] > currentInterval[1]
,则表示nextInterval
与currentInterval
不重叠。 这意味着当前的currentInterval
已经合并完成,可以将其添加到merged
数组中,并用nextInterval
来更新currentInterval
,开始合并一个新的区间。
- 如果重叠: 如果
-
-
添加最后一个区间:
- 当循环结束时,通常最后一个合并好的区间还存储在
currentInterval
中,需要将其添加到merged
数组。
- 当循环结束时,通常最后一个合并好的区间还存储在
-
返回结果:
- 返回
merged
数组,其中包含所有合并后的不重叠区间。
- 返回
注意事项
- 排序: 排序是解决方案的关键。 确保使用正确的排序函数
(a, b) => a[0] - b[0]
,它按照起始位置升序排列。 如果不排序,或者排序方式不正确,则合并逻辑将会出错。 - 重叠条件: 重叠的条件是
nextInterval[0] <= currentInterval[1]
。 必须正确理解此条件,才能判断两个区间是否重叠。 - 更新结束位置: 重叠时,必须选择
currentInterval
和nextInterval
中较大的结束位置,以确保合并后的区间能覆盖所有重叠的部分。 - 最后一个区间: 千万不要忘记将最后一个合并好的区间添加到
merged
数组。 - 空数组处理: 代码已经正确地处理了空数组的情况。 确保你的代码也考虑到这种情况。
- 数组的不可变性:
sort()
方法会改变原数组。 如果你需要保持原数组不变,可以在排序之前先创建一个数组的副本。 - 区间定义: 必须清楚区间的定义是包含起始位置和结束位置,即
[starti, endi]
包含starti
和endi
这两个端点。
结语
再见!