【LeetCode 热题 100】最长连续序列


精选专栏链接 🔗


欢迎订阅,点赞+关注,每日精进1%,与百万开发者共攀技术珠峰

更多内容持续更新中~



【LeetCode 热题 100】最长连续序列

  • 📝题目描述
  • 💡提示信息
  • [方法一:排序 + 线性扫描](#方法一:排序 + 线性扫描)
  • [方法二:哈希集合 + 智能起点(最优解)](#方法二:哈希集合 + 智能起点(最优解))
  • 总结

📝题目描述

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

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

示例 2:

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

示例 3:

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

💡提示信息

  • 0 <= nums.length <= 10 5 10^5 105;
  • -109 <= nums[i] <= 10 9 10^9 109;

方法一:排序 + 线性扫描

最直观的思路通常是先对数组进行排序。排序后,原本乱序的数字会变得有序,我们只需要一次遍历就能统计出最长的连续长度。

核心思路

  1. 判空处理:如果数组为空,直接返回 0;
  2. 数组排序:使用 Arrays.sort() 对数组进行升序排列、;
  3. 遍历统计:从第二个元素开始遍历,比较当前元素 nums[i] 与前一个元素 nums[i-1];
    • 去重:如果两者相等,说明是重复元素直接跳过(continue)
    • 连续:如果 nums[i] == nums[i-1] + 1,说明数字连续,当前连续长度 currentLen 加 1;
    • 断开:如果不满足上述条件,说明连续性被打断,将 currentLen 重置为 1;
    • 更新最大值:在遍历过程中,时刻维护一个全局最大长度 maxLen;

Java 代码实现如下:

java 复制代码
class Solution {
    public int longestConsecutive(int[] nums) {

        if(nums == null || nums.length == 0){
            return 0;
        }

        // 1. 排序
        Arrays.sort(nums);

        int maxLen = 1;   // 记录最长连续序列长度
        int currentLen = 1;  // 记录当前连续序列长度

        // 2. 线性扫描
        for(int i=1;i<nums.length;i++){
            if(nums[i] == nums[i-1]){
                continue;  // 遇到重复元素,跳过
            }else if(nums[i] == nums[i-1]+1){
                currentLen++;  // 连续,当前长度+1

            }else{
                currentLen = 1;  // 不连续,重置当前长度为1
            }

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

提交代码,运行结果如下:

复杂度分析

  • 时间复杂度:O(N log N)。主要开销在于数组的排序操作,后续的线性扫描仅为 O(N)。注意:这不符合题目要求的 O(N),但在实际面试中可以作为保底解法提出;
  • 空间复杂度:O(1)(取决于排序算法的实现,若忽略排序所需的栈空间则为常数级)。

方法二:哈希集合 + 智能起点(最优解)

为了满足题目要求的 O(N) 时间复杂度,我们需要借助哈希表(HashSet)来实现 O(1) 的快速查找,并采用"智能起点"的策略来避免重复计算。

核心思路

  1. 去重与预处理:首先将所有数字存入 HashSet 中。这一步既去除了重复元素,又为后续的 O(1)查找做好了准备;
  2. 寻找序列起点:遍历集合中的每一个数字 num,我们需要判断它是否是一个连续序列的起点 。判断标准:检查集合中是否存在 num - 1;
    • 如果 num - 1 存在,说明 num 不是起点(它前面还有数),直接跳过;
    • 如果 num - 1 不存在,说明 num 是一个新序列的开头;
  3. 扩展序列:一旦找到起点 num,通过 while 循环不断检查 num + 1、num + 2... 是否存在于集合中,从而计算出该序列的长度;
  4. 更新最大值:计算出的序列长度与 maxLen 比较并更新。

Java 代码实现如下:

java 复制代码
class Solution {
    public int longestConsecutive(int[] nums) {

        if(nums == null || nums.length == 0){
            return 0;
        }

        // 1. 将所有元素存入 HashSet,实现去重和 O(1) 查找
        HashSet<Integer> hashSet = new HashSet<>();
        for(int num:nums){
            hashSet.add(num);
        }

        int maxLen = 1;

        // 2. 遍历集合中的每个数字
        for(int num : hashSet){

            // 3. 核心优化:只有当 num-1 不存在时,num 才是序列的起点
            if(!hashSet.contains(num-1)){
                int currentLen = 1;
                int currentNum = num;

                // 4. 从起点开始,不断向后查找连续的数字
                while(hashSet.contains(currentNum+1)){
                    currentLen++;
                    currentNum++;
                }

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

提交代码,运行结果如下:

复杂度分析

  • 时间复杂度为O(N) 。其中 N 是数组 nums 的长度。虽然代码中有两层循环(外层 for 和内层 while),但实际上每个数字最多只会被访问 2 次;
  • 空间复杂度为O(N) 。算法的核心是使用了 HashSet 来存储数组中的所有元素。
    在最坏情况下(数组中没有重复元素),哈希表需要存储 N 个元素。其他变量只占用常数级别的额外空间;

总结

注意

虽然哈希表法在理论上拥有线性的 O ( N ) O(N) O(N) 时间复杂度,优于排序法的 O ( N log ⁡ N ) O(N \log N) O(NlogN),但在实际运行(特别是数据规模 N N N 较小时)往往更慢。因为在 LeetCode 常规的数据规模下,哈希表法虽然在理论时间复杂度上占优,但单次操作涉及复杂的哈希计算与离散的内存随机访问,开销较大;而 Java 高度优化的底层排序算法凭借其极低的常数开销和 CPU 缓存连续访问优势,足以抵消哈希表法在理论复杂度上的微弱领先,从而在实际运行中表现得更快。

对比

对比维度 排序 + 线性扫描 哈希集合 + 智能起点
时间复杂度 O ( N log ⁡ N ) O(N \log N) O(NlogN) O ( N ) O(N) O(N)
空间复杂度 O ( 1 ) O(1) O(1) O ( N ) O(N) O(N) (需存储所有元素)
实际执行效率 通常更快 相对较慢
适用场景 数据量较小、内存受限或对常数级性能敏感的场景 数据量极大、严格追求线性时间复杂度的场景
面试建议 作为基础解法提出,展示直观思路 作为最优解提出,重点解释"智能起点"去重逻辑

这道题考察的是如何利用哈希集合(HashSet)的特性,通过"只从序列起点开始向后延伸"的巧妙剪枝策略,在 𝑂(𝑁)线性时间内找出最长连续序列。

相关推荐
努力努力再努力wz17 小时前
【Redis入门系列】:从 hashtable到 listpack:深入理解 Hash 底层编码、字段级过期、核心命令与缓存应用
开发语言·数据结构·数据库·c++·redis·算法·缓存
Zxc_17 小时前
模拟退火算法:从固体退火到Rastrigin与TSP,手写一个完整的退火求解器
算法
zhaokuangkuang_17 小时前
Java学习
java·学习·算法
暗冰ཏོ17 小时前
《Vue + React + Java + PHP 项目部署到服务器完整指南》
java·服务器·vue.js·react.js·项目部署
ychqsq17 小时前
29.新生活轨道
经验分享·职场和发展
陈辛chenxin17 小时前
【数据挖掘01】相似度算法大全(万字讲解)
算法·数据挖掘·代理模式
_Aaron___17 小时前
Spring AI 2.0 之后,MCP Server 该按远程企业服务来设计
java·人工智能·spring
NE_STOP17 小时前
Docker--Docker简介及系统架构
java
Daydream.V17 小时前
C++ 入门全攻略:从基础语法到核心特性
java·开发语言·c++
我是一颗柠檬17 小时前
【JDK8新特性】接口默认方法与静态方法Day8
java·开发语言·后端·intellij-idea