LeetCode-Go 题解:228. Summary Ranges 有序数组区间压缩的 Go 实现
LeetCode-Go 题解228. Summary Ranges 有序数组区间压缩的 Go 实现【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go导读本篇围绕 LeetCode-Go 仓库中 0228.Summary-Ranges 题解展开深入剖析「汇总区间Summary Ranges」这一经典数组压缩问题的解法。你将掌握如何用一次线性遍历把「排序且无重复」的整数数组压缩为最小有序的区间字符串列表并通过源码级逐步拆解与测试用例验证理解游标式双指针扫描的编码范式。阅读完本文你既能直接复用仓库中的 Go 实现也能举一反三将其应用到日志时间戳归并、连续编号段压缩等实际场景。题目定义与输入输出约定给定一个排序升序且无重复元素的整数数组nums要求返回恰好覆盖数组中所有数字的最小有序区间范围列表。这里的「恰好覆盖」有两层含义nums中的每个元素恰好被某个区间范围所覆盖不存在整数x属于某个区间范围但x不属于nums。每个区间范围[a, b]按如下规则输出为字符串条件输出格式含义a ! ba-b区间包含多个连续整数a ba单元素区间直接输出该数字官方示例示例 1nums [0,1,2,4,5,7]输出[0-2,4-5,7]。[0,2] -- 0-2 [4,5] -- 4-5 [7,7] -- 7示例 2nums [0,2,3,4,6,8,9]输出[0,2-4,6,8-9]。[0,0] -- 0 [2,4] -- 2-4 [6,6] -- 6 [8,9] -- 8-9示例 3nums []输出[]空数组无区间可输出。示例 4nums [-1]输出[-1]。示例 5nums [0]输出[0]。数据约束0 nums.length 20数组允许为空nums[i]取值范围为-2^31到2^31 - 1即 32 位有符号整数的完整范围需要关注加法是否会溢出详见下文边界分析所有元素唯一且数组按升序排列。核心思路游标式单次线性扫描原文档给出的解题思路非常凝练「简单题。按照题意用一个游标变量累加寻找连续的区间。一旦出现了中断就按照题意格式输出。」这个思路的本质是一次O(n)的线性扫描具体分为三步锚定区间起点用left记录当前区间的第一个元素下标向后探测连续性游标i不断向后移动只要满足nums[i-1] 1 nums[i]说明相邻元素构成连续整数继续延伸区间一旦等式不成立说明连续序列被「中断」当前区间到此为止按格式输出区间若left ! i-1区间内不止一个元素输出a-b否则输出单个元素a然后从下一个元素开始寻找新区间。由于数组已排序且无重复「连续性」可以只用相邻两数的差值是否为 1 来判定无需借助任何哈希表或额外数据结构。整个算法只遍历数组一遍属于标准的单指针 区间端点双下标模式。Go 源码逐行解析仓库中的核心实现在 228. Summary Ranges.go完整代码如下package leetcode import ( strconv ) func summaryRanges(nums []int) (ans []string) { for i, n : 0, len(nums); i n; { left : i for i; i n nums[i-1]1 nums[i]; i { } s : strconv.Itoa(nums[left]) if left ! i-1 { s - strconv.Itoa(nums[i-1]) } ans append(ans, s) } return }下面逐段剖析其设计要点1. 命名返回值(ans []string)函数使用命名返回值ans内部直接append并最后return裸返回。这种写法让「结果就是返回值」的意图一目了然与 LeetCode-Go 仓库整体遵循的 Google Go 风格指南一致。2. 外层循环for i, n : 0, len(nums); i n; {}注意这里没有第三个迭代语句游标i的推进完全由内层循环完成。每次外层循环进入时i都指向一个「新区间的起点」或已越过末尾循环体负责把从i开始的连续区间完整消化掉。3. 内层循环连续区间探测left : i for i; i n nums[i-1]1 nums[i]; i { }先用left : i锚定当前区间起点下标然后i从left的下一个位置开始探测循环条件nums[i-1]1 nums[i]是核心判定它验证「上一个元素加 1 是否等于当前元素」成立即代表两个相邻元素构成连续整数i继续前进一旦不成立循环退出此时i恰好停在下一个新区间的起点或n处表示数组遍历完毕。这里采用nums[i-1]1 nums[i]而非nums[i]-nums[i-1] 1是刻意规避减法避免在nums[i-1]为-2^31等极端值时产生不必要的负数语义歧义使连续性的判断在 32 位整数全范围内保持语义清晰。4. 区间字符串拼接s : strconv.Itoa(nums[left]) if left ! i-1 { s - strconv.Itoa(nums[i-1]) } ans append(ans, s)strconv.Itoa将整数转为十进制字符串先无条件写入区间左端点若left ! i-1说明区间内至少有 2 个元素i-1是区间右端点的下标则追加-与右端点得到a-b格式否则区间是单元素保持a格式。以示例 1 的nums [0,1,2,4,5,7]为例跟踪执行过程外层轮次lefti 探测结束位置区间输出103元素 4[0,2]0-2235元素 7[4,5]4-5356越界[7,7]7三行代码即完成全部逻辑简洁且无任何冗余状态。边界情况与正确性论证对照题目约束逐类分析边界空数组len(nums) 0外层循环条件i n直接不成立函数返回空切片[]对应示例 3单元素数组left 0内层循环因i n立即失败left i-1即0 0输出单元素字符串对应示例 4、示例 5全部连续如[1,2,3]内层循环一路走到底最终输出一个区间1-3全部孤立如[1,3,5]每个元素自成一个区间输出[1,3,5]负数strconv.Itoa对负数的输出天然带-号如[-3,-2,0]输出[-3--2,0]无需额外处理整数极值约束允许nums[i]为-2^31由于判断式写为nums[i-1]1-2^31 1仍在 int 范围内不会溢出同时数组长度上限仅 20不存在大规模累加溢出的风险。若想完全避免加法溢出可等价改写为nums[i]-nums[i-1] 1在本题数据范围内两种写法结果一致。复杂度分析时间复杂度O(n)其中n为数组长度。外层与内层循环共享同一个游标i每个元素最多被访问两次一次作为前驱、一次作为当前值总体是严格的线性扫描不存在嵌套回溯空间复杂度O(1)不计输出结果。算法仅使用left、i、n、s等常数个辅助变量结果切片ans是题目要求返回的载体不属于额外辅助空间。测试用例与仓库验证仓库为本题配套了表驱动测试见 228. Summary Ranges_test.go。测试采用 LeetCode-Go 仓库统一的question228/para228/ans228结构体组织用例qs : []question228{ {para228{[]int{0, 1, 2, 4, 5, 7}}, ans228{[]string{0-2, 4-5, 7}}}, {para228{[]int{0, 2, 3, 4, 6, 8, 9}}, ans228{[]string{0, 2-4, 6, 8-9}}}, {para228{[]int{}}, ans228{[]string{}}}, {para228{[]int{-1}}, ans228{[]string{-1}}}, {para228{[]int{0}}, ans228{[]string{0}}}, }这五组用例与 README 中的五个示例一一对应覆盖了「多元素连续区间」「连续与孤立混合」「空数组」「负数单元素」「非负单元素」五种典型输入其中用例 1 验证多段连续区间的拼接与-格式用例 2 验证孤立元素与连续区间交错出现时仍保持升序输出用例 3 验证空数组返回空切片用例 4、5 验证单元素数组输出单个数字字符串。测试运行时会打印每组输入与summaryRanges的实际输出以便人工核对。若要在本地复现验证可在仓库根目录执行 Go 测试命令go test -v ./leetcode/0228.Summary-Ranges/仓库根目录的 gotest.sh 提供了全量测试脚本其内部执行go test -covermodeatomic -coverprofilecoverage.txt ./leetcode/...可对全部题解做覆盖率收集。对本题而言上述五组用例已完整覆盖代码中的两条分支路径连续区间与单元素区间以及循环的两个出口中断与越界。从本题延伸区间压缩的通用范式summaryRanges所体现的「锚定左端点 → 线性探测右边界 → 一次性输出区间」三步法是区间类问题的通用骨架可平滑迁移到以下场景日志时间戳归并把离散的日志时间点合并为「9:00-9:05」式的时间段列表连续编号段压缩将学号、工号、IP 段等连续编号压缩为区间表示便于存储与展示区间合并预处理作为「合并区间」「插入区间」等题目的前置扫描手段。核心心法只有一个因为输入有序所以连续性判定退化为相邻差值的比较又因为无重复比较结果只有「连续」与「中断」两种状态天然对应区间边界。小结本题输入是排序且无重复的数组因此可用单次线性扫描解决时间复杂度O(n)、空间复杂度O(1)输出格式二选一a-b表示连续多元素区间a表示单元素区间负数的-号由strconv.Itoa天然处理仓库实现 228. Summary Ranges.go 通过「外层锚点 内层探测」的双层循环共享同一游标五组测试用例228. Summary Ranges_test.go完整覆盖了空数组、单元素、混合区间等边界该解法体现的「找区间端点、一次性消费」思路是处理有序数据区间压缩问题的可复用范式。【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考