题目:
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
题解:
排序后好处理,先贴代码(Go):
type Intervals [][]int
func (k Intervals) Len() int {
return len(k)
}
func (k Intervals) Less(i, j int) bool {
return k[i][0] < k[j][0]
}
func (k Intervals) Swap(i, j int) {
k[i][0], k[j][0] = k[j][0], k[i][0]
k[i][1], k[j][1] = k[j][1], k[i][1]
}
func merge(intervals [][]int) [][]int {
var result [][]int
var k Intervals = intervals
sort.Sort(k)
left := k[0][0]
right := k[0][1]
for _, interval := range k {
if interval[0] <= right {
right = max(right, interval[1])
} else {
result = append(result, []int{left, right})
left = interval[0]
right = interval[1]
}
}
result = append(result, []int{left, right})
return result
}
func max(a int, b int) int {
if a > b {
return a
}
return b
}
首先我们将 intervals
中的元素看作一个单元,则这个单元有两个主要属性,即左端点和右端点。
我们理解题意,有点像合并重叠单元从而寻找连通分量
的数量的意思。我们这里定义 连通分量
为不再与数组中任何其他单元重叠的一个单元。
如果两个单元 [a,b]
,[c,d]
重叠,则需要满足判定式: a < c && b > c
或者 a > c && d > a
,需要满足哪个条件取决于谁的左端点更靠左。
我们可以通过对 intervals
排序,保证单元的左端点升序,即固定了判定式中的一个条件,即固定了 a < c
或者 a > c
。之后只需要考虑 b > c
和 d > a
即可。
排序后,我们现在只需要在遍历 intervals
过程中,比较第一个单元的右端点和第二个单元的左端点的值的大小,前者大于等于后者,可合并。合并后单元的右端点取两者的右端点的最大值。
持续合并过程,直到第一个单元的右端点小于第二个单元的左端点,则单元不可合并。则第一个单元就是所谓的 连通分量
了,记录一下。继续进行下一个 连通分量
的查找,直到遍历完成,我们就得到了所有的 连通分量
了。
复杂度分析:
时间复杂度:O(nlogn)
,其中 n
为区间的数量。除去排序的开销,我们只需要一次线性扫描,所以主要的时间开销是排序的 O(nlogn)
。
空间复杂度:O(logn)
,其中 n
为区间的数量。这里计算的是存储答案之外,使用的额外空间。O(logn)
即为排序所需要的空间复杂度
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。