LeetCode 128. 最长连续序列:O (n) 时间的哈希集合 + 剪枝解法全解析

  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

示例 3:

输入:nums = [1,0,1,2]

输出:3

提示:

  • 0 <= nums.length <= 10(5)
  • -10(9) <= nums[i] <= 10(9)

二、思路

因为本题有时间复杂度O(n)的要求,所以不能排序(排序的时间复杂度至少为 O(n log n)

于是通过「哈希集合」实现快速查找,并通过「剪枝」避免重复遍历。
核心思路:

是对于nums中的元素x,先判断x-1是否在数组中,来找到起点,以此时的x为起点,判断x+1,x+2 ...是否在数组中。
关键观察:

一个连续序列的「起点」满足:x-1 不存在于数组中(比如序列 [1,2,3,4] 的起点是 1,因为 0 不在数组中)。

  • 若 x-1 存在,则 x 不是起点,无需遍历以 x 为起点的连续序列(避免重复计算);
  • 若 x-1 不存在,则 x 是起点,需遍历 x+1、x+2... 直到不存在,统计序列长度。

为了满足时间复杂度的要求,一定要做的两个优化

1)使用set集合(哈希集合 ),可以以O(1)的时间复杂度来判断数字是否在nums中。

2)找到最开始的x起点,这样其他的点将不进入内部循环

还可以进行剪枝优化

如果现在得到的最长连续序列的长度已经超过了数组长度的一半,则可以break了,因为假如一共10个数,现在的最长已经是6,则后面的总共才4个,就算这4个全部连续,也没有6大,所以没有必要再进行运算。

三、代码

javascript 复制代码
/**
 * @param {number[]} nums
 * @return {number}
 */
var longestConsecutive = function(nums) {
    //转为set去重,实现O(1)查找,同时处理空数组/重复元素场景。
    const st = new Set(nums);
    let ans = 0;
    //遍历去重后的每个元素
    for(const x of st){
        //若x-1存在,则x不是起点,跳过,避免重复遍历,增加时间复杂度
        if(st.has(x-1)){
            continue;
        }
        //此时x是起点,统计连续序列长度
        let y = x+1;
        //使用while遍历,直到连续序列中断
        while(st.has(y)){
            y++;
        }
        //在不连续的数组中和往期的ans打擂台,如[1,2,3,4]和[100,101]
        ans=Math.max(ans,y-x);
        //剪枝优化:当前最长长度已经超过去重后数组长度的一半,剩下的就算全部连续也不可能比现在的最长序列长度长,无需继续遍历
        if(ans*2>=st.size){
            break;
        }
    }
    return ans;
};

四、复杂度

时间复杂度:O(n) ,其中 n 是 nums 的长度。在二重循环中,每个元素至多遍历两次:在外层循环中遍历一次,在内层循环中遍历一次(相加为2n)。所以二重循环的时间复杂度是 O(n) 的。比如 nums=[1,2,3,4],其中 2,3,4 不会进入内层循环,只有 1 会进入内层循环。所以它们不是相乘的关系,而是相加的关系
空间复杂度:O(m)。其中 m 是 nums 中的不同元素个数。

相关推荐
掘金安东尼8 小时前
让 JavaScript 更容易「善后」的新能力
前端·javascript·面试
掘金安东尼8 小时前
用 HTMX 为 React Data Grid 加速实时更新
前端·javascript·面试
灵感__idea10 小时前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
yinuo10 小时前
轻松接入大语言模型API -04
前端
袋鼠云数栈UED团队11 小时前
基于 Lexical 实现变量输入编辑器
前端·javascript·架构
cipher11 小时前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
UrbanJazzerati11 小时前
非常友好的Vue 3 生命周期详解
前端·面试
AAA阿giao11 小时前
从零构建一个现代登录页:深入解析 Tailwind CSS + Vite + Lucide React 的完整技术栈
前端·css·react.js
兆子龙12 小时前
像 React Hook 一样「自动触发」:用 Git Hook 拦住忘删的测试代码与其它翻车现场
前端·架构
兆子龙13 小时前
用 Auto.js 实现挂机脚本:从找图点击到循环自动化
前端·架构