← 返回题目列表

汇总区间怎么把有序数组压缩成连续范围?(LeetCode 228)

高频 简单 第 1 / 24 题 更新于 2026/07/30
区间问题连续区间有序扫描

简化版

汇总区间用一次线性扫描。因为数组有序且无重复,连续段满足 nums[i] == nums[i-1] + 1;遇到不连续的位置就收尾上一段,最后别忘了把末尾段加入答案。

详细版

start 表示当前连续段起点,遍历数组下标 i。如果 i+1 越界,或 nums[i+1] != nums[i] + 1,说明当前连续段在 i 结束,需要输出 [start, nums[i]]。如果起点等于终点,输出单个数字;否则输出 "start->end"

这题看起来简单,但面试常考两个细节:第一,数组可能为空;第二,nums[i] + 1 可能在整型最大值处溢出。更稳的写法是用 long 比较,或改写成 nums[i+1] - nums[i] == 1 时也要注意差值溢出。Java 中可以转 long 后判断。

时间复杂度 O(n),除输出外额外空间 O(1)。本质是区间问题里的“从点生成区间”,和合并区间相反。

完整版教学

一、题目本质是从点集生成区间

输入是一个升序、无重复的整数数组,输出要把连续的数字压缩成区间。比如 [0,1,2,4,5,7] 应变成 ["0->2","4->5","7"]

这类题的核心不是排序,因为输入已经有序;核心是识别“连续段什么时候结束”。只要连续关系被打断,就可以把前面那段输出。

记忆钩子:汇总区间是在“点”上做扫描,遇到断点就把上一段封口。

二、连续段的判定条件

对相邻两个数 a=nums[i]b=nums[i+1],如果 b == a + 1,它们属于同一个连续段;否则当前段在 i 结束。

nums = [0, 1, 2, 4, 5, 7]
        0--1--2  4--5  7
输出:  [0,2], [4,5], [7,7]

因为数组无重复且升序,连续关系只需要检查相邻元素。不需要回头,也不需要维护复杂结构。

三、扫描流程怎么设计

常见写法是维护一个 start,表示当前段的起点。遍历每个下标 i,当发现 i 是当前段末尾时,输出 start..nums[i],再把下一个位置设成新段起点。

start = nums[0]
for i in [0..n-1]:
  if i == n-1 or nums[i+1] != nums[i] + 1:
      emit(start, nums[i])
      if i + 1 < n: start = nums[i+1]

这个流程把“最后一段”统一放进循环,不需要循环结束后再写一段额外逻辑,也就少一个漏加尾段的风险。

四、代码模板

List<String> summaryRanges(int[] nums) {
    List<String> ans = new ArrayList<>();
    if (nums.length == 0) return ans;

    int start = nums[0];
    for (int i = 0; i < nums.length; i++) {
        boolean endOfRange = i == nums.length - 1
            || (long) nums[i + 1] != (long) nums[i] + 1;

        if (endOfRange) {
            if (start == nums[i]) ans.add(String.valueOf(start));
            else ans.add(start + "->" + nums[i]);

            if (i + 1 < nums.length) start = nums[i + 1];
        }
    }
    return ans;
}

这里用 (long) nums[i] + 1 防止 Integer.MAX_VALUE + 1 溢出。虽然很多测试数据不触发,但面试中主动提这点说明边界意识到位。

五、数字例子手推

[0,1,2,4,5,7] 为例:

inums[i]下一个数是否断开输出
001-
112-
2240->2
4574->5
57越界7

输出单点时不能写成 "7->7",题目要求单个数字单独显示。这是格式题的关键细节。

六、和合并区间的关系

题型输入核心动作输出
汇总区间有序点集连续点压缩成段不重叠区间字符串
合并区间若干区间重叠段合并不重叠区间数组
插入区间有序不重叠区间 + 新区间三段扫描更新后的区间数组

汇总区间是区间专题的基础题,它训练的是边界收尾。很多复杂题也要先能稳定维护“当前段起点”和“当前段终点”。

七、常见误区与追问

  • 误区:最后一段会自动输出。 如果只在断点处输出,末尾没有下一个断点,必须用 i == n-1 统一处理。
  • 误区:单点区间也输出 start->end。 题目要求起点等于终点时只输出一个数字。
  • 误区:直接写 nums[i] + 1 不考虑溢出。nums[i] 是最大整数时会溢出,转 long 更稳。
  • 追问:如果数组不是有序的怎么办? 需要先排序并去重,但这会改变题目复杂度和语义。
  • 追问:如果允许重复数字怎么办? 重复数字不表示连续前进,需要先决定重复是否跳过,再维护区间。
  • 追问:为什么时间是 O(n)? 每个元素只被扫描一次,输出总长度不计入额外算法成本时是线性的。

八、加强记忆

汇总区间记住“起点 start + 断点收尾”。相邻差 1 就继续,不连续或到数组末尾就输出当前段;单点输出数字,多点输出 start->end。边界上重点防空数组、末尾漏加和整数溢出。