中等LeetCode 128动画补充中引导学习
最长连续序列
哈希集合:只从起点数
把数组变成哈希集合,然后只从"序列的起点"(值减 1 不在集合里)开始往右数连续长度。
时间复杂度 O(n)空间复杂度 O(n)
题单:面试热题
题目描述
给定一个未排序的整数数组,找出其中数字连续的最长子序列的长度(序列由 +1 递增值构成,不要求原数组里的顺序相邻)。要求时间复杂度 O(n)。
学习目标
能说清为什么只从"序列起点"扩展,并解释每个元素最多被访问两次如何保证 O(n)。
已完成 0 / 6 阶段
诊断
先问:排序为什么不够
排序后扫描相邻元素也能求最长连续序列,为什么题目还要 O(n)?
建议先完成当前阶段(提示 / 检查 / 自评),再进入下一步;也可以直接跳过。
解题思路
核心思想
把数组变成哈希集合,然后只从"序列的起点"(值减 1 不在集合里)开始往右数连续长度。
为什么需要它
排序再扫一遍是 O(n log n),题目要求 O(n) 说明要找线性做法;而"某个数是否出现过"的判断正适合哈希集合。
第一反应:直觉方案
对每个数向左右两侧扩散找 x-1、x+1 是否存在——逻辑自然,但每个数会被反复扩展,实际是 O(n²)。
关键洞察
关键洞察是给扩展加一个"只从起点出发"的限制:如果 x-1 也在集合里,x 一定不是序列起点,直接跳过。只从起点开始向右数,每个元素最多被访问两次,总复杂度回到 O(n)。不重复劳动的关键不只是数据结构,还有"这一步该不该由我做"的判断。
时间复杂度 O(n)空间复杂度 O(n)
易错点
- 每个数都要判断自己是不是起点——跳过非起点才是 O(n) 的关键
- 只需要"存在性"判断,用集合(set)就够了
- 空数组返回 0
参考代码
参考代码
1function longestConsecutive(nums) {
2 const set = new Set(nums);
3 let best = 0;
4 for (const x of set) {
5 if (set.has(x - 1)) continue; // 不是序列起点,跳过
6 let length = 1;
7 while (set.has(x + length)) length += 1;
8 best = Math.max(best, length);
9 }
10 return best;
11}
逐步演示
这道题目前是索引版:题面、解题思路与双语言代码已是完整内容; 逐步动画会按计划补充。