多个重叠区间去重合并问题探讨

174 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

问题

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

思路1

prev 初始为第一个区间,cur 表示当前的区间,res 表示结果数组

1、开启遍历,尝试合并 prev 和 cur,合并后更新到 prev

2、合并后的新区间还可能和后面的区间重合,继续尝试合并新的 cur,更新给 prev

3、直到不能合并 —— prev[1] < cur[0],此时将 prev 区间推入 res 数组

合并的策略

原则上要更新prev[0]和prev[1],即左右端:

prev[0] = min(prev[0], cur[0])

prev[1] = max(prev[1], cur[1])

但如果先按区间的左端排升序,就能保证 prev[0] < cur[0]

所以合并只需这条:prev[1] = max(prev[1], cur[1])

思路2

用贪心算法解决。

区间集合,要将重叠区间合并,需要排序,以便找到重叠区间。

对于区间集合进行排序有两个选择,对于左边界或者右边界进行排序。

排序后,找重叠部分,对于左边界进行排序,如果一个区间的右边界大于等于下一个区间的左边界,表明这两个区间有重叠部分,要将前一个区间的右边界拓宽,选择这两个区间中较大的右边界。

如果一个区间的右边界小于下一个区间的左边界,这两个区间没有重叠,将前一个区间加入结果集合中。

遍历结束后还要将最后一个区间加入结果集合中。

易错点

我们是先合并,遇到不重合再推入 prev。 当考察完最后一个区间,后面没区间了,遇不到不重合区间,最后的 prev 没推入 res。 要单独补上。

上代码

func merge(intervals [][]int) [][]int {
	sort.Slice(intervals, func(i, j int) bool {
		return intervals[i][0] < intervals[j][0]
	})
	res := [][]int{}
	prev := intervals[0]

	for i := 1; i < len(intervals); i++ {
		cur := intervals[i]
		if prev[1] < cur[0] { // 没有一点重合
			res = append(res, prev)
			prev = cur
		} else { // 有重合
			prev[1] = max(prev[1], cur[1])
		}
	}
	res = append(res, prev)
	return res
}
func max(a, b int) int {
	if a > b { return a }
	return b
}