Medium
题目描述
给定一个未排序的整数数组 nums,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
示例 3:
输入:nums = [1,0,1,2]
输出:3
提示:
- 0 <= nums.length <= 10⁵
- -10⁹ <= nums[i] <= 10⁹
解题思路
这道题要求在 O(n) 时间内找到最长连续序列,有三种主要解法:
方法一:哈希表(推荐) 使用哈希表存储所有数字,然后对每个数字,只有当它是序列起点时(即 num-1 不存在)才开始向右扩展。这样每个数字最多被访问两次,保证了 O(n) 复杂度。
方法二:排序后遍历 先排序后去重,然后遍历数组统计连续序列长度。时间复杂度 O(n log n),不满足题目要求但思路简单。
方法三:并查集 将相邻数字进行合并,最后统计最大连通分量。实现复杂,时间复杂度接近 O(n)。
哈希表方法最优:通过识别序列起点避免重复计算,既保证了 O(n) 时间复杂度,又实现简洁。关键在于理解"只从序列起点开始扩展"这一优化思想。
代码实现
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> numSet(nums.begin(), nums.end());
int maxLength = 0;
for (int num : numSet) {
// 只有当num是序列的起点时才开始计算
if (numSet.find(num - 1) == numSet.end()) {
int currentNum = num;
int currentLength = 1;
// 向右扩展序列
while (numSet.find(currentNum + 1) != numSet.end()) {
currentNum++;
currentLength++;
}
maxLength = max(maxLength, currentLength);
}
}
return maxLength;
}
};
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
num_set = set(nums)
max_length = 0
for num in num_set:
# 只有当num是序列的起点时才开始计算
if num - 1 not in num_set:
current_num = num
current_length = 1
# 向右扩展序列
while current_num + 1 in num_set:
current_num += 1
current_length += 1
max_length = max(max_length, current_length)
return max_length
public class Solution {
public int LongestConsecutive(int[] nums) {
HashSet<int> numSet = new HashSet<int>(nums);
int maxLength = 0;
foreach (int num in numSet) {
// 只有当num是序列的起点时才开始计算
if (!numSet.Contains(num - 1)) {
int currentNum = num;
int currentLength = 1;
// 向右扩展序列
while (numSet.Contains(currentNum + 1)) {
currentNum++;
currentLength++;
}
maxLength = Math.Max(maxLength, currentLength);
}
}
return maxLength;
}
}
var longestConsecutive = function(nums) {
const numSet = new Set(nums);
let maxLength = 0;
for (const num of numSet) {
// 只有当num是序列的起点时才开始计算
if (!numSet.has(num - 1)) {
let currentNum = num;
let currentLength = 1;
// 向右扩展序列
while (numSet.has(currentNum + 1)) {
currentNum++;
currentLength++;
}
maxLength = Math.max(maxLength, currentLength);
}
}
return maxLength;
};
复杂度分析
| 复杂度 | 哈希表方法 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(n) |
时间复杂度分析:
- 构建哈希表:O(n)
- 遍历哈希表:O(n),每个数字最多被访问两次(一次作为起点检查,一次在序列扩展中)
- 总体:O(n)
空间复杂度分析:
- 哈希表存储所有数字:O(n)