128. 最长连续序列(Longest Consecutive Sequence)
频次 ★★★★ · 难度 🟡 · 高频:字节/阿里
题目
给定未排序整数数组,找出数字连续(值连续,位置无关)的最长序列长度。要求 O(n) 时间。
示例:
输入: [100,4,200,1,3,2]
输出: 4 (连续序列 1,2,3,4)
思路
排序做是 O(n log n),题目逼你用哈希:全部数字入 HashSet,然后只从”序列起点”向右数——一个数 x 是起点当且仅当 x-1 不在集合里。从起点开始 x+1, x+2, ... 逐个查集合延伸,记录最长长度。
关键在”只从起点展开”:每个数最多被访问两次(一次判起点、一次被某条序列扫过),总时间 O(n)。
代码
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int n : nums) set.add(n);
int best = 0;
for (int x : set) {
if (set.contains(x - 1)) continue; // 不是起点,跳过(去重的关键)
int len = 1;
while (set.contains(x + len)) len++; // 从起点向右延伸
best = Math.max(best, len);
}
return best;
}复杂度
- 时间:O(n) —— 每个元素判起点 O(1);只有真起点才展开,所有展开步数之和等于各序列总长 ≤ n
- 空间:O(n) —— HashSet
边界条件
- 空数组:返回 0
- 全部重复(
[1,1,1]):set 去重后长度 1 - 单调递减输入:不影响,集合无序,按起点逻辑照常工作
变式
- 要求返回序列本身:起点展开时顺带记录区间
[x, x+len-1] - 数据流版/支持动态插入:用并查集把
x与x+1合并,size 数组维护连通块大小
易错点
- 不判起点直接对每个数向右展开 → 最坏 O(n²)(
[1,2,3,...,n]每个点都扫到尾),这是本题最常见的”看似 O(n) 实则超时” - 遍历时应遍历
set而不是原数组,否则大量重复元素会重复做起点判断(不影响正确性但浪费) while (set.contains(x + len))中用len做偏移,避免修改x后影响外层判断
面试追问
- 为什么复杂度是 O(n) 而不是 O(n²)? 回答要点:展开只发生在起点,且每条序列只被它唯一的起点展开一次,展开总步数 = 所有序列长度之和 ≤ n
- 如果内存放不下所有数呢? 外部排序后线性扫描(退回 O(n log n)),或按值域分片多轮处理——哈希方案的前提是数据能进内存
关联题
- 同套路:1. 两数之和 —— 同为”哈希以空间换时间”,把查找从 O(n) 压到 O(1)
- 进阶:并查集解法(
x与x+1合并),并查集专题见并查集 - 易混:560. 和为 K 的子数组 —— 同用哈希但存的是前缀和,本题存的是元素本身
- 知识点:HashSet 底层就是 HashMap 的 key 集,见集合框架