LeetCode 128. 最长连续序列:巧用哈希表实现 O(n) 复杂度
题目描述
给定一个未排序的整数数组 nums
,找到其中最长的连续数字序列的长度。要求算法的时间复杂度为 O(n)。
示例:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长连续序列是 [1, 2, 3, 4]
,长度为 4。
核心思路
暴力解法(如排序后遍历)的时间复杂度为 O(n log n),不满足题目要求。
优化思路:利用哈希表(HashSet)快速查询元素是否存在,避免重复遍历。
- 去重处理:将所有元素存入哈希表,去除重复值。
- 仅处理序列起点:对于每个元素
num
,如果num-1
不在哈希表中,说明num
可能是一个连续序列的起点。 - 延伸序列:从起点开始,向后查找
num+1, num+2, ...
,统计最长连续序列长度。
代码实现
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num); // 去重,O(n)
}
int result = 0;
for (int num : set) {
// 只有当 num 是某个连续序列的起点时,才进入循环
if (!set.contains(num - 1)) {
int currentNum = num;
int currentRes = 1;
// 向后延伸序列:num+1, num+2, ...
while (set.contains(currentNum + 1)) {
currentNum++;
currentRes++;
}
result = Math.max(result, currentRes);
}
}
return result;
}
力扣通过截图
步骤解析
-
去重与哈希表存储:
使用HashSet
存储所有元素,去除重复值。例如,输入[1,2,2,3]
会被处理为{1,2,3}
。 -
寻找序列起点:
遍历哈希表中的每个元素num
,如果num-1
不在集合中,说明num
是某个连续序列的最小值。例如:- 输入
[100,4,200,1,3,2]
的哈希表为{1,2,3,4,100,200}
。 1
是起点(因为没有0
),而2
不是(因为1
存在)。
- 输入
-
统计最长序列:
从起点num
开始,通过while
循环向后查找连续的数,直到无法继续。例如:- 起点为
1
时,连续序列为1,2,3,4
,长度为 4。 - 起点为
100
时,序列长度为 1。 - 最终取最大值
4
。
- 起点为
时间复杂度分析
- 去重操作:
O(n)
,遍历数组一次。 - 遍历哈希表:每个元素最多被访问两次(作为起点被处理一次,作为其他序列的非起点被跳过一次)。
- 总时间复杂度:
O(n)
,满足题目要求。
边界与示例验证
-
空数组:
输入nums = []
,哈希表为空,直接返回0
。 -
单元素数组:
输入nums = [5]
,返回1
。 -
包含重复元素:
输入nums = [1,0,1,2]
,哈希表为{0,1,2}
。最长序列为0,1,2
,长度 3。
对比其他方法
方法 | 时间复杂度 | 核心思路 | 适用场景 |
---|---|---|---|
哈希表法(本文) | O(n) | 仅处理序列起点 | 大规模数据 |
排序法 | O(n log n) | 排序后遍历统计 | 小规模数据 |
并查集 | O(n) | 合并连续区间 | 复杂连续结构处理 |
总结
- 关键技巧:通过哈希表快速判断元素是否存在,避免无效遍历。
- 优化核心:仅处理可能的序列起点,确保每个元素被访问次数为常数次。
- 适用场景:数据规模大、要求严格线性时间复杂度的问题。