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 中的不同元素个数。

相关推荐
元亓亓亓2 小时前
LeetCode热题100--763. 划分字母区间--中等
算法·leetcode·职场和发展
Dream it possible!2 小时前
LeetCode 面试经典 150_回溯_全排列(100_46_C++_中等)
c++·leetcode·面试·回溯
鹿角片ljp2 小时前
力扣206.反转链表-双指针法(推荐)
算法·leetcode·链表
GISer_Jing2 小时前
AI赋能前端:从核心概念到工程实践的全景学习指南
前端·javascript·aigc
|晴 天|2 小时前
前端事件循环:宏任务与微任务的深度解析
前端
用户4445543654262 小时前
Android开发中的封装思路指导
前端
LYFlied2 小时前
【每日算法】LeetCode 70. 爬楼梯:从递归到动态规划的思维演进
算法·leetcode·面试·职场和发展·动态规划
一起养小猫2 小时前
LeetCode100天Day2-验证回文串与接雨水
java·leetcode
YoungHong19922 小时前
面试经典150题[073]:从中序与后序遍历序列构造二叉树(LeetCode 106)
leetcode·面试·职场和发展