class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int ans = 0;
for (int x : set) {
if (!set.contains(x - 1)) {
int temp = 1;
int cur = x;
while (set.contains(cur + 1)) {
temp++;
cur++;
}
ans = Math.max(ans, temp);
}
}
return ans;
}
}
一、 算法核心设计思想
该算法的核心在于解决两个效率瓶颈:去重与快速查找、避免重复枚举序列。
1. 哈希表去重与常数级查找
在未排序数组中查找一个元素是否存在,常规的暴力查找需要 O(n)时间,而排序需要 O(n \log n)时间。本解法首先将所有元素存入 HashSet:
-
去重: 消除数组中重复数字对计数造成的干扰(如示例 3 中的重复
1)。 -
常数查找:
HashSet的contains操作在平均情况下的时间复杂度为 O(1),这为后续的连续性检测提供了高效率支持。
2. 核心剪枝逻辑:定位序列起点
算法的核心突破点在于 if (!set.contains(x - 1)) 这一行判断。
-
逻辑含义: 对于集合中的某个数字 x,如果 x - 1 已经存在于集合中,说明 x 绝对不是某个连续序列的开头,它只是某个更长序列的中间元素。
-
执行策略: 只有当 x - 1 不在集合中时,才认定 x 是一个序列的起点(最小值),此时才启动
while循环向后延伸查找 x + 1, x + 2, \dots。 -
效果: 这一步剪枝彻底改变了算法的复杂度,确保了每个连续序列只会被完整遍历一次。
二、 算法执行流程拆解
以示例 1 为例:nums = [100, 4, 200, 1, 3, 2]
步骤 1:构建哈希集合
遍历 nums,存入 HashSet,此时 set = {100, 4, 200, 1, 3, 2}。
步骤 2:遍历集合并计数
外层循环遍历 set 中的每个元素 x(以输入 nums = [100, 4, 200, 1, 3, 2] 为例):
| 当前元素 x | set.contains(x - 1) 结果 | 是否触发 while 循环 | 内部 while 循环过程与计数 | 局部长度 temp | 全局最大长度 ans |
| 100 | contains(99) → 否 | 是 (起点) | 查找 101 不存在,循环直接结束 | 1 | max(0, 1) = 1 |
| 4 | contains(3) → 是 | 否 (跳过) | 无(4 不是序列起点,跳过) | - | 1 |
| 200 | contains(199) → 否 | 是 (起点) | 查找 201 不存在,循环直接结束 | 1 | max(1, 1) = 1 |
| 1 | contains(0) → 否 | 是 (起点) |
依次查找 2, 3, 4 均存在,5 不存在。 连续序列为: | 4 | max(1, 4) = 4 |
| 3 | contains(2) → 是 | 否 (跳过) | 无(3 不是序列起点,跳过) | - | 4 |
| 2 | contains(1) → 是 | 否 (跳过) | 无(2 不是序列起点,跳过) | - | 4 |
最终返回: ans = 4
三、 复杂度分析
1. 时间复杂度:$O(n)$
虽然代码结构中存在一个 while 循环嵌套在 for 循环内部,通常这种结构可能导致 $O(n^2)$ 的复杂度,但由于剪枝条件的存在,其总体时间复杂度为 $O(n)$。
-
外层循环: 遍历
set中的每个独立元素,共执行 $n$ 次(准确说是 $U$ 次, $U$ 为去重后的元素个数,$U \le n$)。 -
内层
while循环: 只有当元素是序列的起点时才会触发。对于任何一个数字,它要么是起点而被移入while循环进行后续递增遍历,要么是中间项直接被if语句跳过。 -
总遍历次数: 每一个数字在整个算法生命周期中,最多只会在外层循环被访问一次,在内层
while循环中被访问一次。因此,所有元素被访问的累加次数不会超过 $2n$ 次。 -
结论: 算法的整体时间复杂度为稳定且线性的 $O(n)$。
2. 空间复杂度:$O(n)$
-
空间消耗源: 算法显式地创建了一个
HashSet来存储输入数组中的元素。 -
消耗量级: 在最坏情况下(数组中所有元素均不重复),
HashSet需要存储全部 $n$ 个元素。 -
结论: 算法的空间复杂度为 $O(n)$。
1355

被折叠的 条评论
为什么被折叠?



