LeetCode 228简单数组扫描
汇总区间 图解题解
这道题到底在问什么
给定升序无重复数组 nums,返回所有汇总区间。连续区间写成 start->end,单个数字写成它自己,按从小到大输出。
- 输入
- nums=[0,1,2,4,5,7]
- 输出
- ["0->2","4->5","7"]
- 输入
- nums=[1,3,5]
- 输出
- ["1","3","5"](都不连续)
最优解:一步一步想明白
- 3记住「看下一个是不是 +1:是就延伸,不是就收尾」,下面每帧都在套它。
- 4扫到 0(紫色),绿色是当前正在生长的区间。看它的下一个 1 是不是正好等于 0+1=1?
- 51 正好是 0+1,连续!绿色区间往右长一格,包进 1,起点仍是 0。继续往后看。
- 6扫到 1(紫色),绿色是当前正在生长的区间。看它的下一个 2 是不是正好等于 1+1=2?
- 72 正好是 1+1,连续!绿色区间往右长一格,包进 2,起点仍是 0。继续往后看。
- 8扫到 2(紫色),绿色是当前正在生长的区间。看它的下一个 4 是不是正好等于 2+1=3?
- 94 不等于 2+1,断开。这段从 0 连到 2,输出 "0->2"。这段变蓝表示已汇总,下一个数另起一段。
- 10扫到 4(紫色),绿色是当前正在生长的区间。看它的下一个 5 是不是正好等于 4+1=5?
- 115 正好是 4+1,连续!绿色区间往右长一格,包进 5,起点仍是 4。继续往后看。
- 12扫到 5(紫色),绿色是当前正在生长的区间。看它的下一个 7 是不是正好等于 5+1=6?
- 137 不等于 5+1,断开。这段从 4 连到 5,输出 "4->5"。这段变蓝表示已汇总,下一个数另起一段。
- 14扫到 7(紫色),绿色是当前正在生长的区间。看它的下一个 8 是不是正好等于 7+1=8?
- 158 正好是 7+1,连续!绿色区间往右长一格,包进 8,起点仍是 7。继续往后看。
- 16扫到 8(紫色),绿色是当前正在生长的区间。看它的下一个 9 是不是正好等于 8+1=9?
- 179 正好是 8+1,连续!绿色区间往右长一格,包进 9,起点仍是 7。继续往后看。
- 18扫到 9(紫色),绿色是当前正在生长的区间。看它的下一个 11 是不是正好等于 9+1=10?
- 1911 不等于 9+1,断开。这段从 7 连到 9,输出 "7->9"。这段变蓝表示已汇总,下一个数另起一段。
- 20扫到 11(紫色),绿色是当前正在生长的区间。看它的下一个 13 是不是正好等于 11+1=12?
- 2113 不等于 11+1,断开。这段只有 11 一个数,落单,输出 "11"。这段变蓝表示已汇总,下一个数另起一段。
- 22扫到最后一个 13(紫色)。后面没有数了,当前这段绿色区间必须收尾。
- 23到末尾。这段只有 13 一个数,落单,输出 "13"。这段变蓝表示已汇总,下一个数另起一段。
- 24扫完全程,整个数组被切成 5 段连续区间:0->2、4->5、7->9、11、13。一遍扫描、不回头,就把所有区间汇总好了。
⚠️ 容易写错的地方
✗ 错:单个数字也写成 x->x
✓ 对:起点等于终点时只写它自己
题目要求落单的数写成单个数字,不带箭头
✗ 错:忘了处理最后一段
✓ 对:走到末尾也要把当前区间收尾
末尾的区间没有「下一个」来触发断开,需单独收口
✗ 错:用相减判断连续时整型溢出
✓ 对:比较 nums[i+1] == nums[i]+1 而非相减
边界值如 2^31−1 相减会溢出,逐个判 +1 更稳
完整代码(Python / C++ / Java)
Python
from typing import List
class Solution:
def summaryRanges(self, nums: List[int]) -> List[str]:
ans = []
i = 0
while i < len(nums):
start = nums[i]
while i + 1 < len(nums) and nums[i + 1] == nums[i] + 1:
i += 1
if start == nums[i]:
ans.append(str(start))
else:
ans.append(f"{start}->{nums[i]}")
i += 1
return ansC++
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> ans;
int n = nums.size();
for (int i = 0; i < n; ++i) {
int start = nums[i];
while (i + 1 < n && nums[i + 1] == nums[i] + 1) ++i;
if (start == nums[i]) ans.push_back(to_string(start));
else ans.push_back(to_string(start) + "->" + to_string(nums[i]));
}
return ans;
}
};Java
import java.util.*;
class Solution {
public List<String> summaryRanges(int[] nums) {
List<String> ans = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
int start = nums[i];
while (i + 1 < nums.length && nums[i + 1] == nums[i] + 1) i++;
if (start == nums[i]) ans.add(String.valueOf(start));
else ans.add(start + "->" + nums[i]);
}
return ans;
}
}复杂度
时间
O(n)
每个元素只被看一次
空间
O(1)
不算输出,只用起点等常数变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 汇总区间 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么用「比下一个」而不是「比上一个」来分段?+
两者都行,本质都是检测断点。比下一个的好处是:一旦发现 nums[i+1] 不连续,当前段就能立刻在 i 处收尾,逻辑顺着扫描方向走,代码更直观。
如果数组可能有重复或不保证升序怎么办?+
题目保证升序无重复,所以「+1」判断成立。若可能重复,需先去重;若无序,需先排序,再套同一套分段逻辑。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 汇总区间 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。