【LeetCode刷题日记】119.最长连续序列(字节面试题最新)

🔥个人主页:北极的代码(欢迎来访)

🎬作者简介:java后端学习者

❄️个人专栏:苍穹外卖日记SSM框架深入JavaWeb

命运的结局尽可永在,不屈的挑战却不可须臾或缺!

前言:这里给大家带来一道群友面试字节的手撕题,感觉很不错,我一开始也没想到更好的方法(因为博主是个刚开始刷算法的小白),因此拿出来和大家分享一下,一起交流。

摘要:

摘要:本文分享了一道字节跳动的面试题------寻找未排序整数数组中最长连续序列的长度。

题目要求时间复杂度为O(n),传统排序法(O(nlogn))不符合要求。

核心解法是使用HashSet去重并实现O(1)查询,通过判断当前数字是否为序列起点(即num-1不存在),然后向后延伸统计序列长度。相比排序法(时间换空间),哈希表解法以空间换时间,满足O(n)复杂度要求。

文章提供了两种实现代码,并解释了哈希表快速查找的原理。

题目背景:119.最长连续序列

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

示例 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

提示:

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

进阶: 可以设计并实现时间复杂度为 O(n)的解决方案吗?

这里面试官要求的就是时间复杂度为O(n)


题目解析:

首先拿到这个题目

我们想到的可能是先给数组排序,Arrays.sort(); 遍历一遍之后,统计当前连续序列的长度,并更新最大值,但是这样并不符合面试官的要求,这种方法,排序的时间复杂度为O(NlogN),遍历是O(N),总复杂度为O(NlogN),所以这个方法并不适用。


那到这里,思路就比较乱了,唯一一个容易想到的解题思路竟然不符合要求,这时友善的面试官提醒了一下,用哈希表。

那我们来分析一下,用哈希表能解决吗,以及怎么使用哈希表。

分析一下题目,找出最长连续的序列,这类问题通常要求时间复杂度为O(N),然后我们用的排序法的时间复杂度是不符合要求的,那就代表此时的数组是无序的状态,此时问题就变成了要在无序数组中,快速判断连续的序列,也就是快速判断某个数字的邻居是否存在。

想要在数组中快速找到某个元素,同时还不能依靠数组的下标 ,因为数组的元素并不是有序的,也就是时间复杂度为O(1),这就已经指向哈希表了。

如果不用哈希表的话,就要对每个数字都遍历一次去寻找邻居,显然时间复杂度为O(N2) ,同时题目还有第二层逻辑,看给定的第二个示例,数组里面有重复元素,看到重复这两个字,我们瞬间就想到了HsahSet的自动去重。

大体的方向我们确定了,但是还有一个问题,我们要找最长的连续序列,那这个起点我们怎么找,或者说怎么确定

我们之间从头开始判断,判断这个元素-1在不在哈希表中,如果在,说明当前元素就不是起始元素,(当前元素-1)才是起始元素,然后接着判断,这样我们就确定了第一个起始序列元素,然后我们找后面的元素,就是**(起始元素+1)因为是连续的,不断地+1,判断哈希表中有没有这个元素,同时每次循环的时候都要记录当前序列的长度,从而最后通过比较找到最长的序列。**


关于如何不依赖数组的下标和数组有序:

核心原理:哈希函数

普通的数组查找,就像是在一排没有编号的格子里找东西,你必须从第一个格子开始一个个看**(遍历),或者利用二分查找(需要排序)**。

而哈希表的做法完全不同。它有一个哈希函数。
当你想要存储或查找一个元素(比如数字 100 )时,哈希表不会去遍历,而是把 100 扔进这个公式里算一下。

它不需要排序,也不需要从头遍历。它通过计算,直接定位到了存储位置。这就是为什么它的时间复杂度是 O(1)(瞬间找到)。

不依赖"物理下标",但它有"逻辑位置"

提到的不依赖下标,其实是指它不像数组那样依赖连续的物理内存下标。
数组:数据必须紧挨着放,下标 0 旁边必须是下标 1 。
哈希表:底层其实还是一个数组,但它允许数据"跳跃"存放。

通过哈希函数计算出来的那个位置,就是它在哈希表里的逻辑下标。

不管你的数据原本是多少,经过公式一算,都会被映射到数组的某个具体下标上。

存:把数据扔进哈希函数,算出一个位置,放进去。
找:把数据再扔进哈希函数,算出同一个位置,直接去那里拿。

这就是为什么它既不需要数据有序,也不需要遍历下标,就能实现极速查找的原因。

具体的原理在我之前的章节有提过:【LeetCode刷题日记】哈希表:从0基础到实战全解析

感兴趣的朋友可以看看。

题目答案:

java 复制代码
import java.util.HashSet;
import java.util.Set;

class Solution {
    public int longestConsecutive(int[] nums) {
        // 边界情况处理
        if (nums == null || nums.length == 0) {
            return 0;
        }

        // 1. 将所有数字存入 HashSet,自动去重并提供 O(1) 查找
        Set<Integer> numSet = new HashSet<>();
        for (int num : nums) {
            numSet.add(num);
        }

        int maxLen = 0;

        // 2. 遍历集合中的每个数字
        for (int num : numSet) {
            // 3. 只有当 num 是序列的起点时(即 num-1 不在集合中),才开始计数
            if (!numSet.contains(num - 1)) {
                int currentNum = num;
                int currentLen = 1;

                // 4. 从起点开始,不断查找下一个连续数字
                while (numSet.contains(currentNum + 1)) {
                    currentNum += 1;
                    currentLen += 1;
                }

                // 5. 更新最大长度
                maxLen = Math.max(maxLen, currentLen);
            }
        }

        return maxLen;
    }
}

直接排序:

java 复制代码
import java.util.Arrays;

class Solution {
    public int longestConsecutive(int[] nums) {
        // 1. 边界情况处理
        if (nums == null || nums.length == 0) {
            return 0;
        }

        // 2. 排序:让连续的数字在数组中相邻
        Arrays.sort(nums);

        int maxLen = 1;      // 记录最长序列的长度,至少为1
        int currentLen = 1;  // 记录当前正在统计的序列长度

        // 3. 从第二个元素开始遍历
        for (int i = 1; i < nums.length; i++) {
            // 情况一:遇到重复数字,直接跳过,不改变当前长度
            if (nums[i] == nums[i - 1]) {
                continue;
            }
            // 情况二:当前数字和前一个数字连续
            else if (nums[i] == nums[i - 1] + 1) {
                currentLen++;
            }
            // 情况三:序列中断,重置当前长度,并更新最大长度
            else {
                maxLen = Math.max(maxLen, currentLen);
                currentLen = 1; // 从当前数字开始新的序列
            }
        }

        // 4. 最后再比较一次,防止最长的序列在数组末尾
        return Math.max(maxLen, currentLen);
    }
}

对比一下,排序的方法是时间换空间,哈希表是空间换时间。

结语:如果对你有帮助,请**点赞,关注,收藏,**你的支持就是我最大的鼓励!

相关推荐
spssau2 小时前
非量表问卷信效度分析,用内容效度 + 重测信度评估数据质量
人工智能·算法·机器学习
大G的笔记本2 小时前
redis常用场景-java示例
java·开发语言·redis
成为你的宁宁2 小时前
【Kubernetes Secret 安全配置指南:从创建配置到环境变量、数据卷使用及私有镜像仓库实践】
java·安全·kubernetes
鹏程十八少2 小时前
5. 2026金三银四 吐血整理!Android高级UI 自定义view面试25题,覆盖90%大厂考点
前端·面试·前端框架
xieliyu.2 小时前
Java手搓数据结构:从零模拟实现顺序表增删改查
java·开发语言·数据结构·学习·顺序表
小凡子空白在线学习2 小时前
工作中设计模式内容
java·后端·spring
高林雨露2 小时前
Java开发转kotlin
java·kotlin
Wenzar_2 小时前
# 发散创新:SwiftUI 中状态管理的深度实践与重构艺术 在 SwiftUI 的世界里,**状态驱动 UI 是核心哲学**。但随
java·python·ui·重构·swiftui
我不是懒洋洋2 小时前
【数据结构】二叉树-堆(树的概念、二叉树的概念、顺序结构的结构及实现、堆的实现、堆排序、TopK问题)
c语言·数据结构·c++·经验分享·算法·青少年编程