题目
标题和出处
标题:合并区间
出处:56. 合并区间
难度
5 级
题目描述
要求
给定区间数组 intervals \texttt{intervals} intervals,其中 intervals[i] = [start i , end i ] \texttt{intervals[i] = [start}_\texttt{i}\texttt{, end}_\texttt{i}\texttt{]} intervals[i] = [starti, endi],合并所有重叠的区间,并返回一个不重叠的区间数组,该数组覆盖输入中的所有区间。
示例
示例 1:
输入:
intervals
=
[[1,3],[2,6],[8,10],[15,18]]
\texttt{intervals = [[1,3],[2,6],[8,10],[15,18]]}
intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:
[[1,6],[8,10],[15,18]]
\texttt{[[1,6],[8,10],[15,18]]}
[[1,6],[8,10],[15,18]]
解释:区间
[1,3]
\texttt{[1,3]}
[1,3] 和
[2,6]
\texttt{[2,6]}
[2,6] 重叠, 将它们合并为
[1,6]
\texttt{[1,6]}
[1,6]。
示例 2:
输入:
intervals
=
[[1,4],[4,5]]
\texttt{intervals = [[1,4],[4,5]]}
intervals = [[1,4],[4,5]]
输出:
[[1,5]]
\texttt{[[1,5]]}
[[1,5]]
解释:区间
[1,4]
\texttt{[1,4]}
[1,4] 和
[4,5]
\texttt{[4,5]}
[4,5] 可被视为重叠区间。
数据范围
- 1 ≤ intervals.length ≤ 10 4 \texttt{1} \le \texttt{intervals.length} \le \texttt{10}^\texttt{4} 1≤intervals.length≤104
- intervals[i].length = 2 \texttt{intervals[i].length} = \texttt{2} intervals[i].length=2
- 0 ≤ start i ≤ end i ≤ 10 4 \texttt{0} \le \texttt{start}_\texttt{i} \le \texttt{end}_\texttt{i} \le \texttt{10}^\texttt{4} 0≤starti≤endi≤104
解法
思路和算法
为了合并数组 intervals \textit{intervals} intervals 中的所有重叠的区间,需要首先将所有的区间排序,然后判断是否有重叠的区间,并将重叠的区间合并。
对区间排序的方法是,首先将区间按照开始位置升序排序,如果存在多个区间的开始位置相同,则按照结束位置降序排序。排序之后,相同开始位置的多个区间中,第一个区间是最长的区间,对于每个开始位置只需要保留最长的区间。
由于无法事先知道合并后剩余多少个区间,因此使用列表存储合并后的区间。遍历排序后的数组 intervals \textit{intervals} intervals,首先将首个区间(即 intervals [ 0 ] \textit{intervals}[0] intervals[0])添加到列表中,然后对其余的区间依次判断是否需要和已有的区间合并,并更新列表。
由于相同开始位置的多个区间只保留最长的区间,因此对于遍历到的每个区间,需要判断该区间与数组 intervals \textit{intervals} intervals 中的上一个区间的开始位置是否相同,如果相同则跳过。当前区间不跳过时,将当前区间记为 curr \textit{curr} curr,将列表中的最后一个区间记为 prev \textit{prev} prev。由于已经对数组 intervals \textit{intervals} intervals 排序,因此 prev \textit{prev} prev 的开始位置一定小于 curr \textit{curr} curr 的开始位置。比较 curr \textit{curr} curr 的开始位置和 prev \textit{prev} prev 的结束位置,执行如下操作。
-
如果 curr \textit{curr} curr 的开始位置小于等于 prev \textit{prev} prev 的结束位置,则 prev \textit{prev} prev 和 curr \textit{curr} curr 重叠,需要合并,合并之后的区间的开始位置是 prev [ 0 ] \textit{prev}[0] prev[0](因为 prev [ 0 ] < curr [ 0 ] \textit{prev}[0] < \textit{curr}[0] prev[0]<curr[0]),结束位置是 max ( prev [ 1 ] , curr [ 1 ] ) \max(\textit{prev}[1], \textit{curr}[1]) max(prev[1],curr[1])。更新 prev [ 1 ] \textit{prev}[1] prev[1] 的值,即可实现合并,不需要将 curr \textit{curr} curr 添加到列表中。
-
如果 curr \textit{curr} curr 的开始位置大于 prev \textit{prev} prev 的结束位置,则 prev \textit{prev} prev 和 curr \textit{curr} curr 不重叠,因此将 curr \textit{curr} curr 添加到列表中。
遍历结束之后,将列表转成数组返回。
代码
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
} else {
return b[1] - a[1];
}
});
List<int[]> mergedList = new ArrayList<int[]>();
mergedList.add(intervals[0]);
int length = intervals.length;
for (int i = 1; i < length; i++) {
int[] curr = intervals[i];
int[] prev = mergedList.get(mergedList.size() - 1);
if (curr[0] == prev[0]) {
continue;
}
if (curr[0] <= prev[1]) {
prev[1] = Math.max(prev[1], curr[1]);
} else {
mergedList.add(curr);
}
}
return mergedList.toArray(new int[mergedList.size()][]);
}
}
复杂度分析
-
时间复杂度: O ( n log n ) O(n \log n) O(nlogn),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。排序需要 O ( n log n ) O(n \log n) O(nlogn) 的时间,排序后遍历数组合并区间需要 O ( n ) O(n) O(n) 的时间,时间复杂度是 O ( n log n ) O(n \log n) O(nlogn)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。存储合并后的区间的列表需要 O ( n ) O(n) O(n) 的空间。