一分钟解决 | 高频面试算法题——最长连续序列(哈希表)

一、前置知识(可跳过)

javascript中的Set

1. 高效的查找操作:

  • Sethas() 方法: Set 提供了 has(value) 方法来检查一个元素是否存在于集合中。 这个操作的平均时间复杂度是 O(1)。 这意味着无论 Set 中有多少个元素,检查一个元素是否存在的时间几乎是恒定的。
  • 相比之下,数组的 includes() 方法: 如果你使用数组而不是 Set,并且使用 includes() 方法来查找某个元素是否存在,那么 includes() 方法的时间复杂度是 O(n),其中 n 是数组的长度。 这意味着在最坏情况下,你需要遍历整个数组才能确定元素是否存在。

2. 避免重复元素:

  • Set 只存储唯一的元素。 如果你多次向 Set 中添加相同的元素,Set 会自动忽略重复的元素。 在寻找连续序列时,重复的数字不会影响结果,所以 Set 可以帮助你自动去重。

二、题目描述------最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) **的算法解决此问题。

示例 1:

ini 复制代码
输入: nums = [100,4,200,1,3,2]
输出: 4
解释: 最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

示例 2:

ini 复制代码
输入: nums = [0,3,7,2,5,8,4,6,0,1]
输出: 9

示例 3:

ini 复制代码
输入: nums = [1,0,1,2]
输出: 3

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109

三、题解

js 复制代码
/**
 * @param {number[]} nums
 * @return {number}
 */
var longestConsecutive = function(nums) {
    if (!nums || nums.length === 0) {
        return 0;
    }

    const numSet = new Set(nums); // 使用 Set 实现 O(1) 的查找效率
    let longestStreak = 0;

    for (const num of numSet) {
        // 只需从序列的起始数字开始计算长度
        if (!numSet.has(num - 1)) {
            let currentNum = num;
            let currentStreak = 1;

            // 沿着序列一直向下查找
            while (numSet.has(currentNum + 1)) {
                currentNum += 1;
                currentStreak += 1;
            }

            longestStreak = Math.max(longestStreak, currentStreak);
        }
    }

    return longestStreak;
};

核心思路

1.使用 Set 实现快速查找:

javascript 复制代码
-   `Set` 数据结构允许你以平均 O(1) 的时间复杂度检查一个元素是否存在。 这意味着,无论 Set 中有多少个元素,检查一个元素是否存在的时间几乎是恒定的。
-   通过将数组中的所有数字添加到 Set 中,我们可以避免使用 `includes()` 或其他线性查找方法,从而减少查找相邻数字的时间复杂度。

2.只从序列的起始数字开始计算:

markdown 复制代码
-   这个优化至关重要。 我们只从序列的起始数字开始计算序列的长度。 序列的起始数字指的是,它的前一个数字(`num - 1`)不存在于 Set 中的数字。
-   如果一个数字不是一个序列的起始数字,我们就可以跳过它,因为它肯定已经被包含在其他序列中。
-   通过只从序列的起始数字开始计算,我们确保每个数字只会被当做连续序列的一部分计算一次。这对于保证 O(n) 的时间复杂度至关重要。

详细解释

  1. 初始化:

    • 首先,处理空数组或 null 的情况,直接返回 0。
    • 创建一个 numSet (Set 对象):将数组中的所有数字添加到 Set 中。 Set 是一种特殊的数据结构,它允许我们以平均 O(1) 的时间复杂度检查一个元素是否存在。 这是解决时间复杂度问题的关键。
  2. 遍历 Set:

    • 遍历整个 numSet。 对于 Set 中的每个数字 num,我们检查它是否是一个序列的起始数字。
  3. 检查序列起始:

    • if (!numSet.has(num - 1)): 这是关键优化。 我们只从序列的起始数字开始计算序列长度。 如果 num - 1 存在于 numSet 中,那么 num 肯定不是一个序列的起始数字,因为 num - 1 才是。 如果当前数 num 不是一个序列的起始数字, 就跳过本次循环,处理下一个数字。 确保每个数字只会被当做连续序列的一部分计算一次, 这对于保证 O(n) 的时间复杂度至关重要。
  4. 计算序列长度:

    • 如果 num 是一个序列的起始数字,那么我们就开始沿着序列一直向下查找:

      • currentNum = num;: 将当前数字设置为该起始数字。
      • currentStreak = 1;: 初始化当前序列的长度为 1。
      • while (numSet.has(currentNum + 1)): 只要 currentNum + 1 存在于 numSet 中,就说明序列还在继续。
      • currentNum += 1;: 向下移动到序列中的下一个数字。
      • currentStreak += 1;: 增加序列的长度。
  5. 更新最长序列长度:

    • longestStreak = Math.max(longestStreak, currentStreak);: 在每次找到一个序列后,将当前序列的长度与 longestStreak 进行比较,并更新 longestStreak
  6. 返回结果:

    • 最后,返回 longestStreak,即最长连续序列的长度。

实列与展示

四、结语

再见!

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
你撅嘴真丑4 小时前
第九章-数字三角形
算法
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
uesowys4 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
ValhallaCoder4 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮5 小时前
AI 视觉连载1:像素
算法
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
智驱力人工智能5 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算