LC100_128

50 阅读3分钟

LC100_128

128. 最长连续序列 - 力扣(LeetCode)

题目大意: 给定一个未排序的整数数组 nums,找出其中数字连续的最长序列的长度。

例如: [100, 4, 200, 1, 3, 2],最长连续序列是 [1, 2, 3, 4],长度为 4

Key constraints:

  1. Time complexity: This is the greatest challenge, which means we cannot use the O(NlogN) solution based on sorting

排序再查找,时间复杂度是 O(NlogN),不符合要求。要达到 O(N),通常会想到哈希表 (Hash Table),因为它提供了平均 O(1) 的查找和插入


核心思想:用哈希表存储所有数字,并只从“连续序列的起点”开始探索

First Step: Save all numbers into a hash set

第一步:将所有数字存入哈希集合 (Set):

  1. 快速地判断一个数字是否存在于数组中。std::unordered_set 在 C++ 中提供平均 O(1) 的查找效率
  2. nums 数组中的所有元素都插入到 std::unordered_set<int> 中。这步操作的时间复杂度是 O(N)

第二步:遍历数组,寻找连续序列的起点

  1. 遍历原始数组 nums 中的每一个数字 num
  2. 对于每个 num,我们想判断它是不是一个连续序列的起点
  3. 如何判断起点? 如果 num - 1 不在哈希集合中,那么 num 就是一个潜在的连续序列的起点

第三步:从起点开始向后探索

  1. 确定 num 是一个起点,那么就以 num 为起点,开始向后查找连续的数字
  2. 维护一个 current_num = numcurrent_streak = 1
  3. 不断检查 current_num + 1 是否在哈希集合中:
    1. 如果在,说明序列还在继续,current_num 增加 1,current_streak 增加 1
    2. 如果不在,说明序列断了,当前 current_streak 就是以 num 为起点的最长连续序列长度
  4. 用一个 max_streak 变量来记录迄今为止找到的最长的连续序列长度,每次探索完一个序列后更新 max_streak = std::max(max_streak, current_streak)

code

class Solution {
public:
    int longestConsecutive(std::vector<int>& nums) {
        // 如果数组为空,直接返回0
        if (nums.empty()) {
            return 0;
        }

        // 1. 将所有数字存入哈希集合,方便 O(1) 查找
        std::unordered_set<int> num_set(nums.begin(), nums.end());

        int max_streak = 0; // 记录找到的最长连续序列长度

        // 2. 遍历原始数组中的每个数字
        for (int num : nums) {
            // 3. 判断当前数字是否是连续序列的起点
            // 如果 num - 1 不在集合中,说明 num 是一个新序列的起点
            if (num_set.find(num - 1) == num_set.end()) {
                // 是起点,开始向后探索这个序列
                int current_num = num;
                int current_streak = 1;

                // 检查 current_num + 1 是否存在,直到序列中断
                while (num_set.count(current_num + 1)) {
                    current_num++;
                    current_streak++;
                }

                // 更新最长序列长度
                max_streak = std::max(max_streak, current_streak);
            }
        }
        
        return max_streak;
    }
};

复杂度分析:

  1. 时间复杂度:O(N)
    1. N 个元素插入 unordered_set:平均 O(N)
    2. 遍历 N 个元素:O(N)
    3. 在内部的 while 循环中,每个数字 x (num_set.count(x + 1)) 只会在其作为某个连续序列的一部分时被访问一次。虽然有嵌套循环,但总的 num_set.count() 调用次数以及 current_num++ 的次数,加起来不会超过 N 次。因此,总体时间复杂度是线性的
  2. 空间复杂度:O(N)
    1. unordered_set 最多会存储 N 个数字