[LeetCode刷题]128.最长连续序列(从零开始的java题解)

题目描述

题目链接:128. 最长连续序列 - 力扣(LeetCode)

定一个未排序的整数数组 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 <= 105
  • -109 <= nums[i] <= 109

题目分析

先理解什么是"连续序列"?

连续序列就是像 1,2,3,4 这样,每个数比前一个数大1的序列。注意:

  • 不需要在数组中是连续的(位置可以乱)

  • 数字可以重复,但重复的不计入长度

  • 比如 [1,2,2,3] 的最长连续序列是 [1,2,3],长度是3

为什么不能直接排序?

排序的时间复杂度是O(nlogn),题目要求O(n),所以我们需要想别的办法。

解题思路

核心思想:用HashSet实现O(1)查找

如果我们能快速知道一个数字是否存在,那么找连续序列就简单了。HashSet的查找时间复杂度是O(1),正好符合要求。

关键优化:只从序列的起点开始找

比如数组 [100,4,200,1,3,2]

  • 数字2:它前面有1,所以它不是起点(1,2,3,4这个序列应该从1开始找)

  • 数字3:它前面有2,也不是起点

  • 数字4:它前面有3,也不是起点

  • 数字1:它前面没有0,所以它是起点!

这样我们只从起点开始找,避免了重复计算,保证了O(n)的时间复杂度。

代码实现(详细注释版)

java 复制代码
class Solution {
    public int longestConsecutive(int[] nums) {
        // 步骤1:处理边界情况
        // 如果数组为空或长度为0,直接返回0
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        // 步骤2:创建HashSet,将数组中的所有元素存入
        // HashSet有两个作用:1.去重 2.提供O(1)的查找
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            set.add(nums[i]);
        }
        
        int longest = 0;  // 记录最长连续序列的长度
        
        // 步骤3:将set转换成数组,方便用传统for循环遍历
        // 因为set不能直接用下标访问,所以先转成数组
        Integer[] setArray = set.toArray(new Integer[0]);
        
        // 步骤4:遍历每一个数字
        for (int i = 0; i < setArray.length; i++) {
            int num = setArray[i];  // 当前要处理的数字
            
            // 步骤5:关键优化!只从连续序列的起点开始找
            // 如果num-1存在,说明num不是起点,直接跳过
            // 比如数字2,因为1存在,所以2不是起点
            if (!set.contains(num - 1)) {
                int currentNum = num;      // 当前数字,用于往后查找
                int currentLength = 1;     // 当前连续序列的长度,初始为1
                
                // 步骤6:往后找连续的数字
                // 只要下一个数字存在,就一直找下去
                while (set.contains(currentNum + 1)) {
                    currentNum++;           // 数字加1
                    currentLength++;        // 长度加1
                }
                
                // 步骤7:更新最长长度
                // 如果当前找到的长度比之前记录的最长长度还大,就更新
                if (currentLength > longest) {
                    longest = currentLength;
                }
            }
        }
        
        // 步骤8:返回最长长度
        return longest;
    }
}

代码执行过程演示

让我们用示例1来一步步看代码是如何执行的:

输入nums = [100, 4, 200, 1, 3, 2]

第1步:创建HashSet

java 复制代码
setArray = [100, 4, 200, 1, 3, 2]  // 转换成数组方便遍历

第2步:转换成数组

java 复制代码
setArray = [100, 4, 200, 1, 3, 2]  // 转换成数组方便遍历

第3步:遍历数组中的每个数字

处理第1个数字:100

  • 检查99在set中吗? → 不在

  • 所以100是起点

  • 往后找101? → 不在set中

  • 当前长度 = 1

  • longest = max(0, 1) = 1

处理第2个数字:4

  • 检查3在set中吗? → 在(set中有3)

  • 所以4不是起点,跳过

处理第3个数字:200

  • 检查199在set中吗? → 不在

  • 所以200是起点

  • 往后找201? → 不在set中

  • 当前长度 = 1

  • longest = max(1, 1) = 1

处理第4个数字:1(关键!)

  • 检查0在set中吗? → 不在

  • 所以1是起点

  • 往后找2? → 在set中,长度=2,当前数字变成2

  • 往后找3? → 在set中,长度=3,当前数字变成3

  • 往后找4? → 在set中,长度=4,当前数字变成4

  • 往后找5? → 不在set中,停止

  • 当前长度 = 4

  • longest = max(1, 4) = 4

处理第5个数字:3

  • 检查2在set中吗? → 在

  • 不是起点,跳过

处理第6个数字:2

  • 检查1在set中吗? → 在

  • 不是起点,跳过

最终结果

java 复制代码
longest = 4  // 最长连续序列 [1,2,3,4] 的长度

图解算法流程

java 复制代码
原始数组:[100, 4, 200, 1, 3, 2]
放入Set:{100, 4, 200, 1, 3, 2}

遍历过程(只从起点开始找):
┌─────────┬────────────┬───────────────┬────────────┬─────────┐
│  数字   │ 是否是起点 │   向后查找    │ 当前长度   │ 最长长度 │
├─────────┼────────────┼───────────────┼────────────┼─────────┤
│   100   │ 是(无99)   │ 101? ✗        │     1      │    1    │
│   4     │ 否(有3)    │ 跳过          │     -      │    1    │
│   200   │ 是(无199)  │ 201? ✗        │     1      │    1    │
│   1     │ 是(无0)    │ 2→3→4? ✓     │     4      │    4    │
│   3     │ 否(有2)    │ 跳过          │     -      │    4    │
│   2     │ 否(有1)    │ 跳过          │     -      │    4    │
└─────────┴────────────┴───────────────┴────────────┴─────────┘

最终最长长度 = 4

总结

  1. 核心数据结构:HashSet,提供O(1)的查找时间

  2. 关键技巧:只从连续序列的起点开始查找

  3. 算法步骤

    • 去重:将所有数字存入HashSet

    • 找起点:如果num-1不存在,则num是起点

    • 向后延伸:一直找num+1、num+2...直到找不到

    • 更新最大值

相关题目推荐

  • 存在重复元素
  • 存在重复元素 II
  • 最长连续递增序列
  • 最长和谐子序列

如果这篇文章对你有帮助,欢迎点赞、收藏、关注!
你的支持是我持续创作的动力!

有什么问题欢迎在评论区留言,我会尽力解答!

相关推荐
亓才孓1 小时前
【MyBatis Exception】SQLSyntaxErrorException(按批修改不加配置会报错)
java·开发语言·mybatis
xiaoye-duck1 小时前
《算法题讲解指南:优选算法-双指针》--05有效三角形的个数,06查找总价值为目标值的两个商品
c++·算法
亓才孓1 小时前
【MyBatis Runtime Exception】自动驼峰映射对Map不生效,应该在查询中起别名
java·windows·mybatis
ArturiaZ1 小时前
【day31】
开发语言·c++·算法
xiaoye-duck1 小时前
《算法题讲解指南:优选算法-双指针》--07三数之和,08四数之和
c++·算法
没有bug.的程序员1 小时前
调试艺术进阶:从断点内核到日志动态化的高效问题定位深度实战指南
java·调试·断点·日志动态化
渣瓦攻城狮2 小时前
互联网大厂Java面试:Spring、微服务与消息队列技术详解
java·redis·spring·微服务·消息队列·面试指南·程序员面试
琢磨先生David2 小时前
Java每日一题
数据结构·算法·leetcode
im_AMBER2 小时前
Leetcode 125 验证回文串 | 判断子序列
数据结构·学习·算法·leetcode