在问 · 算法题解

228. 汇总区间

题目描述

输入一个严格递增的整数数组 nums,其中没有重复的值。

把数组中的数分成若干段,每段都是一串连续的整数 [a,b](包含两端)。要求每个数恰好属于一段,任何一段里都不能出现 nums 之外的数。在此前提下,段数要尽量少。

按从小到大的顺序返回这些段组成的字符串列表。某段的 a != b 时写成 "a->b";a == b 时只写 "a"。数组为空时返回空列表。

示例 1
输入:nums = [0,1,2,4,5,7]
输出:["0->2","4->5","7"]

解释:三段分别是 [0,2]、[4,5]、[7,7],对应 "0->2"、"4->5"、"7"。

示例 2
输入:nums = [0,2,3,4,6,8,9]
输出:["0","2->4","6","8->9"]

解释:四段分别是 [0,0]、[2,4]、[6,6]、[8,9]。

数据范围

  • 0 <= nums.length <= 20
  • -2^31 <= nums[i] <= 2^31 - 1
  • nums 中的数两两不同。
  • nums 已按升序排好。

解题思路

数组有序且无重复,所以一段连续整数在数组里一定是相邻的一串。用 i 标记一段的起点,j 从 i 出发不断向右延伸,只要下一个数恰好比当前大 1 就继续。延伸停止时 nums[i..j] 就是一个最长连续段:i == j 输出单个数,否则输出 "nums[i]->nums[j]"。然后从 j+1 开始找下一段。

为什么正确

每次外层循环开始时,nums[0..i-1] 已被 res 中的区间恰好覆盖,且每个区间都无法再向右延长。

复杂度分析

时间 O(n)(每个元素只被 j 经过一次),除结果外空间 O(1)。

易错点

单个数字不要写成 "7->7";判断连续时用 nums[j+1] == nums[j] + 1,在 C++/Java 中要防止 nums[j] + 1 溢出(INT_MAX 时);数组为空时直接返回空列表。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def summaryRanges(self, nums: List[int]) -> List[str]:
        res = []
        i, n = 0, len(nums)
        while i < n:
            j = i
            while j + 1 < n and nums[j + 1] == nums[j] + 1:
                j += 1
            if i == j:
                res.append(str(nums[i]))
            else:
                res.append(str(nums[i]) + "->" + str(nums[j]))
            i = j + 1
        return res

载入编辑器,自己跑一遍 →

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →