【LeetCode每日一题】56. 合并区间

每日一题

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 时底层数组频繁扩容,稍微提高效率。

相关推荐
你撅嘴真丑4 小时前
第九章-数字三角形
算法
uesowys4 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
ValhallaCoder4 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮4 小时前
AI 视觉连载1:像素
算法
智驱力人工智能5 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
孞㐑¥6 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
月挽清风6 小时前
代码随想录第十五天
数据结构·算法·leetcode
XX風6 小时前
8.1 PFH&&FPFH
图像处理·算法
NEXT066 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
代码游侠7 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法