Skip to content

最长连续序列

LeetCode 官方题目链接

1. 题目呈现

难度等级:🟡 中等
核心考察点:哈希表、并查集

给定一个未排序的整数数组 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


2. 解题思路拆解

方法:哈希集合 (Set)

题目要求 $O(n)$ 的时间复杂度,这意味着我们不能使用 $O(n \log n)$ 的排序算法。

我们可以利用 哈希集合 (Set) 的 $O(1)$ 查找特性来解决:

  1. 去重与快速查找:首先将数组中的所有元素放入 Set 中,去除重复元素,并允许我们在 $O(1)$ 时间内判断一个数是否存在。
  2. 寻找序列起点:遍历 Set 中的每一个元素 num
    • 如果我们发现 num - 1 存在于 Set 中,说明 num 肯定不是一个连续序列的起点(因为前面还有数),我们直接跳过。
    • 如果 num - 1 不存在,说明 num 很有可能是一个序列的起点。
  3. 计算序列长度:从起点 num 开始,不断尝试匹配 num + 1, num + 2, ... 是否存在于 Set 中,直到中断。记录下当前的序列长度。
  4. 更新最大值:在遍历过程中,不断更新最大连续序列长度。

这种方法虽然看起来有双重循环,但实际上每个元素最多只会被访问两次(一次是作为起点判断,一次是作为序列的一部分被统计),因此总时间复杂度是 $O(n)$。


3. 代码实现

javascript
/**
 * @param {number[]} nums
 * @return {number}
 */
var longestConsecutive = function(nums) {
    // 1. 使用 Set 去重,并支持 O(1) 查找
    const set = new Set(nums);
    let maxLen = 0;

    // 2. 遍历 Set 中的每个元素
    for (let num of set) {
        // 只有当 num - 1 不存在时,num 才是一个序列的起点
        if (!set.has(num - 1)) {
            let currentNum = num;
            let currentLen = 1;

            // 3. 不断查找下一个连续的数
            while (set.has(currentNum + 1)) {
                currentNum += 1;
                currentLen += 1;
            }

            // 4. 更新最大长度
            maxLen = Math.max(maxLen, currentLen);
        }
    }

    return maxLen;
};

代码执行演示

假设输入 nums = [100, 4, 200, 1, 3, 2]

  1. 初始化 Set{100, 4, 200, 1, 3, 2}
  2. 遍历元素
    • 元素 100:检查 99 是否存在?-> No。是起点。
      • 向后查找:101? -> No
      • 当前长度:1。maxLen = 1
    • 元素 4:检查 3 是否存在?-> Yes。不是起点,跳过。
    • 元素 200:检查 199 是否存在?-> No。是起点。
      • 向后查找:201? -> No
      • 当前长度:1。maxLen = 1
    • 元素 1:检查 0 是否存在?-> No。是起点。
      • 向后查找:2? -> Yes
      • 向后查找:3? -> Yes
      • 向后查找:4? -> Yes
      • 向后查找:5? -> No
      • 当前长度:4。maxLen = 4
    • 元素 3:检查 2 是否存在?-> Yes。不是起点,跳过。
    • 元素 2:检查 1 是否存在?-> Yes。不是起点,跳过。
  3. 返回结果4

4. 复杂度分析

维度描述
时间复杂度$O(n)$。详细解释:外层循环遍历数组中的 $n$ 个元素。对于每个元素 num,只有当它是序列起点(即 num-1 不存在)时,才会进入内层的 while 循环。
关键点在于:数组中的每个元素,最多只会被 while 循环访问一次(作为序列的一部分被计数时)。
例如序列 [1, 2, 3],数字 1 会触发 while 循环访问 23。之后遍历到 23 时,由于它们不是起点,直接跳过。
因此,每个数字最多被访问两次(一次 for 判定,一次 while 计数),总操作次数是线性的 $2n$,即 $O(n)$。
空间复杂度$O(n)$。需要使用哈希集合存储 $n$ 个元素。

Power by VitePress