[LeetCode][Golang] 56. 合并区间

题目:

以数组 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 > cd > a 即可。

排序后,我们现在只需要在遍历 intervals 过程中,比较第一个单元的右端点和第二个单元的左端点的值的大小,前者大于等于后者,可合并。合并后单元的右端点取两者的右端点的最大值。

持续合并过程,直到第一个单元的右端点小于第二个单元的左端点,则单元不可合并。则第一个单元就是所谓的 连通分量了,记录一下。继续进行下一个 连通分量的查找,直到遍历完成,我们就得到了所有的 连通分量 了。

复杂度分析:

时间复杂度:O(nlogn),其中 n 为区间的数量。除去排序的开销,我们只需要一次线性扫描,所以主要的时间开销是排序的 O(nlogn)

空间复杂度:O(logn),其中 n 为区间的数量。这里计算的是存储答案之外,使用的额外空间。O(logn) 即为排序所需要的空间复杂度

你可能感兴趣的:([LeetCode][Golang] 56. 合并区间)