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

一、前置知识(可跳过)

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,即最长连续序列的长度。

实列与展示

四、结语

再见!

相关推荐
开源之眼13 小时前
github star 加星多的从 React 到 Web3D:前端开发者的三维世界入门指南
javascript·面试
数据大魔方13 小时前
【期货量化入门】期权交易入门:从零开始学期权量化(TqSdk完整教程)
数据库·python·mysql·算法·区块链·程序员创富
期货资管源码13 小时前
期货资管分仓软件开发/平台搭建经验分享
经验分享·算法·eclipse·区块链
程序员爱钓鱼13 小时前
Node.js 编程实战:测试与调试 —— Mocha / Jest / Supertest 使用指南
前端·后端·node.js
Xの哲學13 小时前
Linux 实时调度机制深度解析
linux·服务器·网络·算法·边缘计算
fie888913 小时前
基于蚁群算法求解带时间窗的车辆路径问题
数据库·人工智能·算法
一勺菠萝丶13 小时前
芋道项目部署:前端写死后端地址 vs Nginx 反向代理
前端·nginx·状态模式
ytttr87314 小时前
基于人工蜂群算法(ABC)的MATLAB数值计算求解框架
开发语言·算法·matlab
珂朵莉MM14 小时前
2025年睿抗机器人开发者大赛CAIP-编程技能赛-高职组(国赛)解题报告 | 珂学家
java·开发语言·人工智能·算法·机器人
pas13614 小时前
30-mini-vue 更新 element 的 props
前端·javascript·vue.js