【力扣-56. 合并区间 ✨】Python笔记

0 阅读3分钟

一、前置核心知识点

1. 区间问题通用思路

区间类问题的核心是排序 + 遍历合并

  • 先按区间左端点(或右端点)排序,消除无序性
  • 遍历过程中维护一个 “当前合并区间”,与后续区间比较重叠 / 相邻关系
  • 重叠 / 相邻则合并,否则将当前区间加入结果,开始维护新的区间

2. Python 列表排序与 key 参数

  • list.sort(key=..., reverse=False):原地排序
  • key=lambda x: x[0]:按列表元素的 ** 第 0 位(左端点)** 升序排列
  • reverse=True:可改为降序,本题无需降序
  • 作用:让所有区间按左端点从小到大排列,保证遍历时只需和前一个合并区间比较即可

二、经典算法题:合并区间(LeetCode 56)

题目描述

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

示例

  • 输入intervals = [[1,3],[2,6],[8,10],[15,18]]
  • 输出[[1,6],[8,10],[15,18]]
  • 解释:区间 [1,3][2,6] 重叠,合并为 [1,6]

最优解法:排序 + 遍历合并

核心思路

  1. 排序:按区间左端点从小到大排序,保证所有可能重叠的区间都挨在一起

  2. 初始化:将第一个区间加入结果列表,作为 “当前合并区间”

  3. 遍历合并

    • 若当前区间的左端点 ≤ 当前合并区间的右端点 → 重叠 / 相邻,更新合并区间的右端点为两者最大值
    • 若当前区间的左端点 > 当前合并区间的右端点 → 不重叠,将当前合并区间加入结果,开始维护新的区间
  4. 返回结果:遍历结束后,将最后一个合并区间加入结果

代码实现

from typing import List 
class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]: 
        if not intervals:
            return [] 
        # 按区间左端点升序排序
        intervals.sort(key=lambda x: x[0]) 
        merged = [intervals[0]] # 初始化结果列表,放入第一个区间 
        for current in intervals[1:]: 
            last = merged[-1] # 取结果中最后一个已合并的区间 
            # 当前区间左端点 <= 最后一个区间右端点 → 重叠/相邻,合并 
            if current[0] <= last[1]: 
                # 更新右端点为两者最大值 
                merged[-1] = [last[0], max(last[1], current[1])] 
            else: 
            # 不重叠,直接加入结果 
                merged.append(current) 
        return merged

三、关键逻辑详解

1. 排序的必要性

只有按左端点排序后,才能保证:

  • 所有可能与当前区间重叠的区间,一定出现在它之后
  • 只需和结果中最后一个合并区间比较,无需回溯之前的区间

2. 合并判断条件

  • current[0] <= last[1]

    • 重叠:如 [1,3][2,6]
    • 相邻:如 [1,3][3,5](也需要合并为 [1,5]
  • 合并后右端点取最大值:max(last[1], current[1]),保证覆盖完整区间

3. 边界处理

  • 空输入:直接返回空列表
  • 单区间输入:直接返回原区间
  • 全重叠区间:最终合并为一个区间

四、算法复杂度与拓展

复杂度分析

  • 时间复杂度:O (n log n),主要来自排序;遍历为 O (n)
  • 空间复杂度:O (log n) ~ O (n),排序的栈空间 + 结果存储(最坏情况无重叠,需要 O (n))

拓展场景

该思路可直接迁移到:

  • 插入区间:先插入再合并
  • 区间列表的交集:双指针遍历两个排序后的区间列表
  • 删除区间:遍历并拆分重叠区间