LeetCode 57:插入区间(Insert Interval)——一次遍历,把区间问题想清楚

7 阅读3分钟

区间类题目是算法面试和刷题中绕不开的一大类,而 「插入区间」 是其中非常经典、非常有代表性的一道题。

这道题不考花里胡哨的技巧,核心在于:
你能不能把“区间合并”的过程在脑子里跑一遍。

本文会结合完整代码,从「题目理解 → 思路拆解 → 代码分析 → 易错点总结」一步一步讲清楚。


一、题目描述

给你一组 已经按起点升序排列、且 互不重叠 的区间 intervals
再给你一个新区间 newInterval

要求:
newInterval 插入到原来的区间中,并保证最终结果仍然有序、且区间不重叠。

示例:

intervals = [[1,3],[6,9]]
newInterval = [2,5]

结果:
[[1,5],[6,9]]

二、这道题到底在考什么?

这道题本质只做三件事:

  1. newInterval 前面完全不冲突的区间 直接放进结果
  2. newInterval 和可能重叠的区间合并
  3. 后面剩余的区间继续合并或直接放入

重点不在代码,而在于你是否能分清楚这三段区间


三、整体思路拆解

我们按区间与 newInterval 的关系来划分:

第一部分:完全在 newInterval 左边的区间

条件:

interval.end < newInterval.start

这些区间 一定不会和 newInterval 产生任何重叠,可以直接加入结果。


第二部分:处理 newInterval 本身

有两种情况:

  1. 前面没有区间
  2. 前一个区间和 newInterval 有重叠

判断方式:

result 为空
或者
result 最后一个区间的 end < newInterval.start

如果是第 1 种情况:
直接把 newInterval 放进去

如果是第 2 种情况:
说明有重叠,需要合并:

end = max(原 end, newInterval.end)

第三部分:处理 newInterval 后面的区间

对于剩下的每一个区间:

  • 如果和结果最后一个区间不重叠 → 直接加入
  • 如果有重叠 → 合并

四、代码实现(逐行讲解)

完整代码如下:

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        int index = 0;
        LinkedList<int[]> result = new LinkedList<>();

        // 1. 先加入所有在 newInterval 左边的区间
        for (int[] interval : intervals) {
            if (interval[0] < newInterval[0]) {
                result.add(interval);
                index++;
            } else {
                break;
            }
        }

        // 2. 处理 newInterval
        if (result.size() == 0 || result.getLast()[1] < newInterval[0]) {
            result.add(newInterval);
        } else {
            result.getLast()[1] = Math.max(result.getLast()[1], newInterval[1]);
        }

        // 3. 处理剩余区间
        for (int i = index; i < intervals.length; i++) {
            if (result.getLast()[1] < intervals[i][0]) {
                result.add(intervals[i]);
            } else {
                result.getLast()[1] = Math.max(result.getLast()[1], intervals[i][1]);
            }
        }

        return result.toArray(new int[result.size()][]);
    }
}

五、为什么用 LinkedList?

这里使用 LinkedList<int[]> 的原因很简单:

  • 需要频繁访问 最后一个区间
  • getLast()add() 都是 O(1)
  • 写起来语义清晰

当然,用 ArrayList 也可以,只是代码会稍微啰嗦一点。


六、手动走一遍示例,加深理解

示例:

intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]]
newInterval = [4,8]

执行流程:

  1. 加入 [1,2]
  2. 加入 [3,5]
  3. [3,5][4,8] 重叠 → 合并为 [3,8]
  4. [6,7] 重叠 → 合并为 [3,8]
  5. [8,10] 重叠 → 合并为 [3,10]
  6. [12,16] 不重叠 → 直接加入

最终结果:

[[1,2],[3,10],[12,16]]

七、这道题最容易犯的错误

  1. 忘了区间是已经排序好的
  2. 边界判断写成 <=< 出错
  3. 合并时只更新 end,却错误地动了 start
  4. 直接在原数组上改,逻辑变得混乱

八、区间类题目的通用模板

这道题可以总结出一个通用套路:

  1. 排序(本题已给)
  2. 顺序遍历
  3. 看是否和「结果中的最后一个区间」重叠
  4. 不重叠就加,重叠就合并

后续你会发现:

  • 合并区间
  • 插入区间
  • 区间交集

本质都是这个模板的变形。