🧪 目标:把一个有序数组拆解成多个最小连续区间段
🛠️ 技术关键词:双指针、去重、边界判断、字符串拼接、时间复杂度分析
第一章:失踪的数字碎片
大雄一脸疑惑地看着一份看似完整的数字清单 [0, 1, 2, 4, 5, 7]
,问哆啦A梦:
"能不能把它整理成'连续段'?我不想一个一个读!"
哆啦A梦掏出铜锣烧,咀嚼着说:
"你想要的结果是
['0->2', '4->5', '7']
,对吧?"
第二章:初级代码的翻车现场
大雄兴冲冲写下第一版代码:
ini
function summaryRanges(nums: number[]): string[] {
let show = 0
let count = 0
let sArr: string[] = []
for (let fast = 1; fast <= nums.length; fast++) {
if (nums[show + count] + 1 == nums[fast]) {
count++
} else {
if (count == 0) {
sArr.push(`${nums[show]}`)
show += 1
} else {
sArr.push(`${nums[show]}->${nums[show + count]}`)
show += count + 1
count = 0
}
}
}
return sArr
}
问题出现了:
- 😵 如果有重复元素,
[1,1,2]
就直接脑震荡 - 😵 访问
nums[fast]
时,fast == nums.length
会越界 - 😵
"last + 1 == nums[fast]"
判断不严谨:连续值判断并不意味着"index连续 + 值连续" - 😵 逻辑太绕,
show + count
维护困难
第三章:Bug排查 + 优化决策
❓ 为什么会出错?
因为你假设了值是连续的,索引也是连续的。但如果数组里有重复或者空洞,比如 [1,1,2,3,7]
,你就会判断错。
✅ 怎么修?
✅ 方法一:先去重
用 Set
去掉重复值,确保连续性判断不被干扰
✅ 方法二:优化指针与条件
放弃 count
,用 start
记录区间起点,i
遍历时动态判断是否到了"连续段的终点"
第四章:优化代码登场(可读性 + 正确性)
typescript
function summaryRanges(nums: number[]): string[] {
if (nums.length === 0) return []
const result: string[] = []
const uniqueNums = Array.from(new Set(nums)) // 去重避免重复数字干扰
let start = uniqueNums[0]
for (let i = 1; i <= uniqueNums.length; i++) {
// 到数组尾部 or 当前不连续
if (i === uniqueNums.length || uniqueNums[i] !== uniqueNums[i - 1] + 1) {
if (start === uniqueNums[i - 1]) {
result.push(`${start}`)
} else {
result.push(`${start}->${uniqueNums[i - 1]}`)
}
// 更新 start 为下一个段的起点
start = uniqueNums[i]
}
}
return result
}
第五章:为什么要去重?
这点很容易被忽视,但重复数字会让我们误判连续段的"断裂"。
css
例子:nums = [1,1,2,3]
去重后:nums = [1,2,3]
连续段 = ['1->3']
不去重时:1 和 1 会被误判为"断裂" -> ['1', '1->3']
第六章:真的 O(n) 吗?
你可能注意到了:
我们用到了 .sort()
吗?没有!
那为啥还能保证区间是"有序"的?因为题目中已明确:输入数组是有序的!
所以我们只做了一次 O(n) 遍历,并用常数空间(Set 和 result)
最终时间复杂度:
- 去重 + 遍历:O(n)
- 空间复杂度:O(n) (输出区间)
第七章:小哆啦的记忆卡
技术点 | 含义 |
---|---|
Set 去重 | 保证连续判断的准确性 |
双指针(start + i) | 跟踪区间头尾 |
i ≤ len 遍历 + 提前判断断裂 | 确保每一段被完整结算 |
输出 a 或 a->b | 取决于当前段长度 |
🧾 技术启示录
- ✅ 遇到区间合并问题,第一时间想"是否连续 + 是否有重复"
- ✅ 写循环时注意遍历尾部是否要提前触发逻辑
- ✅ 条件逻辑简化结构,减少变量依赖,更可维护
- ✅ 函数要能解释每个逻辑分支"为何而写"
🧨 窗外彩蛋:
胖虎看着自己的 [1,2,2,3,5,6]
,抱怨道:
"怎么我得到的是
["1->3","5->6"]
,不是["1->2","2->3","5->6"]
?"
哆啦A梦一脸无奈:
"你不去重,就像连续剧中插播广告,剧情不顺你能怪我?"