每日一题
2025.8.20
56. 合并区间
题目
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
总体思路
按起点升序(若起点相同则按终点升序)对区间排序。
这样做后,所有可能与某区间重叠的区间都会紧跟在它后面出现,便于线性扫描合并。
用一个变量 current 表示正在合并中的区间(初始化为排序后第一个)。
从左到右依次遍历后续区间 iv:
- 若 iv.start <= current.end,说明重叠/相邻(如 [1,4] 与 [4,5] 也要合并),更新:
current.end = max(current.end, iv.end) - 否则,说明没有重叠:把 current 推入结果数组,然后把 iv 设为新的 current。
 
扫描结束后,把最后一个 current 推入结果,完成合并。
时间复杂度:排序 O(n log n),扫描 O(n),总 O(n log n)
空间复杂度:结果需要 O(k)(k 为合并后区间数);除结果外只用到常数级额外空间。
代码
golang
            
            
              go
              
              
            
          
          // merge 合并所有重叠(或相邻)的区间。
// 输入输出均为 [][]int,其中每个区间为 [start, end]。
func merge(intervals [][]int) [][]int {
	// 1) 特判:空输入或只有一个区间,直接返回
	if len(intervals) <= 1 {
		return intervals
	}
	// 2) 按起点升序排序;若起点相等,按终点升序
	// sort.Slice 使用匿名比较函数,i、j 是索引,返回 true 表示 i 应排在 j 前面
	sort.Slice(intervals, func(i, j int) bool {
		if intervals[i][0] == intervals[j][0] {
			return intervals[i][1] < intervals[j][1]
            // 如果起点一样,就比较终点
		}
        // 否则,谁的起点小谁排前
		return intervals[i][0] < intervals[j][0]
	})
	// 3) 准备结果切片。预分配容量可小优化:最多就是 n 个
	res := make([][]int, 0, len(intervals))
	// 4) current 表示当前正在合并的区间(直接引用排序后的第一个)
	current := intervals[0]   //(current[0],current[1])当前正在合并的区间
	// 5) 线性扫描其余区间
	for i := 1; i < len(intervals); i++ {
		iv := intervals[i]
		// 判断是否重叠/相邻:只要下一个区间的起点 <= 当前区间的终点
		if iv[0] <= current[1] {
			// 可以合并:更新 current 的右端点为更大的那个
			if iv[1] > current[1] {
				current[1] = iv[1]
			}
			// 注意:不立即放入 res,继续尝试与后面的区间合并
		} else {
			// 不重叠:把当前合并结果推入 res,并开始新的 current
			//current := intervals[0] // 当前正在合并的区间
            //iv := intervals[i]      // 循环里取出来的一个新区间
			res = append(res, current)
			current = iv
		}
	}
	// 6) 别忘了把最后一个合并完成的区间放进去
	res = append(res, current)
	return res
}
        
            
            
              go
              
              
            
          
          //无注释代码纯享
func merge(intervals [][]int) [][]int {
    if len(intervals) <= 1 {
        return intervals
    }
    sort.Slice(intervals,func(i, j int) bool {
        if intervals[i][0] == intervals[j][0] {
            return intervals[i][1] < intervals[j][1]
        }
        return intervals[i][0] < intervals[j][0]
    })
    res := make([][]int, 0, len(intervals))
    current := intervals[0]
    for i:=0; i<len(intervals); i++ {
        iv := intervals[i]
        if iv[0] <= current[1] {
            if iv[1] > current[1] {
                current[1] = iv[1]
            }
        }else{
            res = append(res,current)
            current = iv
        }
    }
    res = append(res, current)
    return res
}
        golang知识
- sort.Slice 是什么?
 
Go 标准库里有个 sort 包,可以帮我们对切片(slice)进行排序。
它的常用函数有:
sort.Ints([]int) ------ 排序一维整型切片
sort.Strings([]string) ------ 排序字符串切片
sort.Slice(slice, lessFunc) ------ 最通用的,用来自定义规则排序任意切片。
- sort.Slice 的用法
 
它的函数签名大概是:
            
            
              go
              
              
            
          
          func Slice(slice interface{}, less func(i, j int) bool)
        第一个参数:你要排序的切片(任何类型的都可以)
第二个参数:一个比较函数,形式是 func(i, j int) bool
i、j 是切片里的索引
返回值 true 表示:切片的第 i 个元素应该排在第 j 个元素前面
make([][]int, 0, len(intervals)) 的三个参数
make(类型, 长度, 容量)
类型:[][]int
表示"切片的元素是 []int(区间),所以它是区间的列表"。
举例:[[1,3],[2,6]] 就是 [][]int。
长度:0
说明一开始里面没有任何元素(空切片)。
容量:len(intervals)
这里表示"预留容量 = 区间总数"。
因为最多结果里不会超过输入的数量(比如 4 个区间,合并后最多还是 4 个,不会更多)。
这样预先分配好空间,可以避免 append 时底层数组频繁扩容,稍微提高效率。