LeetCode 第 128 题「最长连续序列」
字数 1055 2025-10-25 23:40:26

我来给你讲解 LeetCode 第 128 题「最长连续序列」


题目描述

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

解题思路

1. 暴力思路(不可行)

如果先排序,再扫描一遍找最长连续序列,时间复杂度是 O(n log n),但题目要求 O(n)。

如果对每个数字,都尝试找它之后的连续数字,最坏情况 O(n²),也不满足要求。


2. 关键观察

我们要找的是连续的数字,例如 [1,2,3,4] 这样的序列。
连续序列的特点是:序列中的最小值 x,在数组中不存在 x-1

例如:

  • 对于数字 1,没有 0,那么可以从 1 开始往后找 2,3,4,...
  • 对于数字 2,存在 1,所以它不可能是某个连续序列的起点,跳过。

这样,每个连续序列我们只从它的起点开始枚举一次,避免重复计算。


3. 算法步骤

  1. 将所有数字放入一个哈希集合(set),以便 O(1) 时间判断某个数是否存在。
  2. 遍历数组中的每个数字 num
    • 如果 num - 1 存在于集合中,说明 num 不是某个连续序列的起点,跳过。
    • 如果 num - 1 不存在,则 num 是起点,开始向后枚举 num+1, num+2, ... 直到某个数不在集合中为止,记录长度。
  3. 所有长度中的最大值即为答案。

4. 为什么是 O(n) 时间复杂度?

虽然有一个内层循环在枚举连续数字,但每个数字最多被内层循环访问一次(因为只有起点才会进入内层循环,并且每个连续序列只被起点枚举一次),所以总时间复杂度是 O(n)。


举例说明

nums = [100,4,200,1,3,2] 为例:

  1. 建立集合:{100,4,200,1,3,2}
  2. 遍历:
    • 100:99 不在集合中,是起点,向后找 101 不在,长度=1。
    • 4:3 在集合中,跳过。
    • 200:199 不在集合中,是起点,向后找 201 不在,长度=1。
    • 1:0 不在集合中,是起点,向后找 2 在,3 在,4 在,5 不在,长度=4。
    • 3:2 在集合中,跳过。
    • 2:1 在集合中,跳过。
  3. 最大长度 = 4。

代码实现(伪代码/思路)

def longestConsecutive(nums):
    if not nums:
        return 0
    
    num_set = set(nums)
    longest = 0
    
    for num in num_set:
        # 只有当 num 是序列起点时才进入内循环
        if num - 1 not in num_set:
            current_num = num
            current_streak = 1
            
            while current_num + 1 in num_set:
                current_num += 1
                current_streak += 1
            
            longest = max(longest, current_streak)
    
    return longest

复杂度

  • 时间复杂度:O(n),每个元素最多被内外层循环各访问一次。
  • 空间复杂度:O(n),用于存储哈希集合。

这样,我们就用 O(n) 时间解决了“最长连续序列”问题。

我来给你讲解 LeetCode 第 128 题「最长连续序列」 。 题目描述 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 要求时间复杂度为 O(n) 。 示例 1: 示例 2: 解题思路 1. 暴力思路(不可行) 如果先排序,再扫描一遍找最长连续序列,时间复杂度是 O(n log n),但题目要求 O(n)。 如果对每个数字,都尝试找它之后的连续数字,最坏情况 O(n²),也不满足要求。 2. 关键观察 我们要找的是 连续的数字 ,例如 [1,2,3,4] 这样的序列。 连续序列的特点是:序列中的最小值 x ,在数组中不存在 x-1 。 例如: 对于数字 1 ,没有 0 ,那么可以从 1 开始往后找 2,3,4,... 。 对于数字 2 ,存在 1 ,所以它不可能是某个连续序列的起点,跳过。 这样,每个连续序列我们只从它的起点开始枚举一次,避免重复计算。 3. 算法步骤 将所有数字放入一个哈希集合(set),以便 O(1) 时间判断某个数是否存在。 遍历数组中的每个数字 num : 如果 num - 1 存在于集合中,说明 num 不是某个连续序列的起点,跳过。 如果 num - 1 不存在,则 num 是起点,开始向后枚举 num+1, num+2, ... 直到某个数不在集合中为止,记录长度。 所有长度中的最大值即为答案。 4. 为什么是 O(n) 时间复杂度? 虽然有一个内层循环在枚举连续数字,但每个数字最多被内层循环访问一次(因为只有起点才会进入内层循环,并且每个连续序列只被起点枚举一次),所以总时间复杂度是 O(n)。 举例说明 以 nums = [100,4,200,1,3,2] 为例: 建立集合: {100,4,200,1,3,2} 。 遍历: 100:99 不在集合中,是起点,向后找 101 不在,长度=1。 4:3 在集合中,跳过。 200:199 不在集合中,是起点,向后找 201 不在,长度=1。 1:0 不在集合中,是起点,向后找 2 在,3 在,4 在,5 不在,长度=4。 3:2 在集合中,跳过。 2:1 在集合中,跳过。 最大长度 = 4。 代码实现(伪代码/思路) 复杂度 时间复杂度:O(n),每个元素最多被内外层循环各访问一次。 空间复杂度:O(n),用于存储哈希集合。 这样,我们就用 O(n) 时间解决了“最长连续序列”问题。