🔥个人主页: Milestone-里程碑
❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>
🌟心向往之行必能至
题目回顾
给定一个未排序的整数数组 nums,我们需要找出其中数字连续的最长序列的长度,并且要求算法的时间复杂度为 O(n)。
示例:
- 输入:
nums = [100,4,200,1,3,2] - 输出:
4 - 解释:最长连续序列是
[1, 2, 3, 4]
思路分析
这道题最直观的想法是先排序再遍历,但排序的时间复杂度是 O (n log n),无法满足题目要求。我们可以用哈希表来优化,核心思路是:
- 用哈希表存储所有数字:这样可以在 O (1) 时间内判断一个数是否存在。
- 只从序列的起点开始计算 :如果一个数
x的前驱x-1不在哈希表中,说明x是一个连续序列的起点,我们就从x开始,不断寻找x+1、x+2...,直到找不到为止。 - 记录最长序列长度:每次找到一个起点,就计算当前序列的长度,并更新全局最长长度。
这个方法的时间复杂度是 O(n),因为每个数字最多被访问两次(一次被遍历,一次在寻找连续序列时被检查)。
完整代码实现
cpp
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
// 将数组元素存入哈希集合,去重并支持O(1)查找
unordered_set<int> hash(nums.begin(), nums.end());
int len = 0;
for (int x : hash) {
// 如果x-1存在,说明x不是序列起点,跳过
if (hash.count(x - 1)) {
continue;
}
// x是起点,开始寻找连续序列
int y = x + 1;
while (hash.count(y)) {
++y;
}
// 更新最长序列长度
len = max(len, y - x);
}
return len;
}
};
代码详解
-
哈希集合初始化:
cpp
unordered_set<int> hash(nums.begin(), nums.end());将数组元素全部存入
unordered_set,自动去重,并且后续的count操作时间复杂度为 O (1)。 -
遍历哈希集合:
cpp
for (int x : hash) { if (hash.count(x - 1)) continue; // ... }这一步是关键优化:只有当
x-1不在集合中时,x才是一个连续序列的起点,我们才会继续计算。这避免了对每个数字都进行一次完整的连续序列查找。 -
计算连续序列长度:
cpp
int y = x + 1; while (hash.count(y)) ++y; len = max(len, y - x);从起点
x开始,不断寻找下一个连续数字y,直到找不到为止。此时y - x就是当前连续序列的长度,我们用它来更新最长长度len。
复杂度分析
- 时间复杂度 :O (n)。虽然有嵌套的
while循环,但每个数字最多被访问两次(一次在for循环中,一次在while循环中),因此总体时间复杂度是线性的。 - 空间复杂度:O (n)。哈希集合需要存储所有数字,空间复杂度为 O (n)。
总结
这道题的核心在于避免重复计算 ,通过判断 x-1 是否存在,我们只从每个连续序列的起点开始计算,从而保证了算法的时间复杂度为 O (n)。这种思路在处理数组去重、连续序列等问题时非常实用。