算法题 最长连续序列

128. 最长连续序列

问题描述

给定一个未排序的整数数组 nums,找出数字连续的最长序列的长度(要求序列元素在原数组中可以不连续相邻)。要求算法的时间复杂度为 O(n)。

示例

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4],长度为 4

算法思路

哈希集合法(最优解)

  1. 核心思想
    利用 HashSet 实现 O(1) 时间复杂度的元素查找,通过识别连续序列的起点(即当前数字的前一个数不在集合中),然后向后扩展计算连续序列长度。

  2. 操作步骤

    1. 将所有数字存入 HashSet
    2. 遍历数组中的每个数字:
      • num-1 不在集合中 → 说明 num 是连续序列起点
      • num 开始向后扩展(num+1, num+2,...),统计连续序列长度
    3. 更新最长连续序列长度

代码实现

import java.util.HashSet;
import java.util.Set;

class Solution {
    public int longestConsecutive(int[] nums) {
        // 创建哈希集合并添加所有元素
        Set<Integer> numSet = new HashSet<>();
        for (int num : nums) {
            numSet.add(num);
        }
        
        int maxLength = 0;  // 记录最长连续序列长度
        
        for (int num : numSet) {
            // 只有当 num 是连续序列起点时才处理(即 num-1 不在集合中)
            if (!numSet.contains(num - 1)) {
                int currentNum = num;          // 当前检查的数字
                int currentLength = 1;         // 当前连续序列长度
                
                // 向后扩展:检查 num+1, num+2, ... 是否存在
                while (numSet.contains(currentNum + 1)) {
                    currentNum++;
                    currentLength++;
                }
                
                // 更新最长连续序列长度
                maxLength = Math.max(maxLength, currentLength);
            }
        }
        return maxLength;
    }
}

注释

  1. 创建哈希集合

    Set<Integer> numSet = new HashSet<>();
    for (int num : nums) {
        numSet.add(num);
    }
    
    • 将所有元素存入 HashSet,实现 O(1) 时间复杂度的元素查找
  2. 识别序列起点

    if (!numSet.contains(num - 1)) {
    
    • 仅当 num 是连续序列起点时处理(前驱数字不存在)
  3. 向后扩展序列

    while (numSet.contains(currentNum + 1)) {
        currentNum++;
        currentLength++;
    }
    
    • 从起点开始向后扩展,统计连续序列长度
  4. 更新最大长度

    maxLength = Math.max(maxLength, currentLength);
    
    • 实时更新全局最长连续序列长度

算法分析

  • 时间复杂度:O(n)
    每个元素最多被访问两次(一次在遍历集合时,一次在向后扩展时),整体 O(n)
  • 空间复杂度:O(n)
    哈希集合存储所有元素

算法过程

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

  1. 构建集合{100, 4, 200, 1, 3, 2}
  2. 遍历元素
    • 10099不存在 → 起点
      向后扩展:101不存在 → 长度=1
    • 43存在 → 跳过
    • 200199不存在 → 起点
      向后扩展:201不存在 → 长度=1
    • 10不存在 → 起点
      向后扩展:2,3,4存在 → 长度=4
    • 32存在 → 跳过
    • 21存在 → 跳过
  3. 输出maxLength=4

边界处理

  • 空数组:直接返回 0
  • 重复元素:HashSet 自动去重,不影响结果
  • 整数边界:处理 Integer.MIN_VALUEInteger.MAX_VALUE 的边界情况

测试用例

public static void main(String[] args) {
    Solution solution = new Solution();
    
    // 测试用例1:标准示例
    int[] nums1 = {100, 4, 200, 1, 3, 2};
    System.out.println("Test 1: " + solution.longestConsecutive(nums1)); // 4
    
    // 测试用例2:有重复元素
    int[] nums2 = {0, 0, 1, 2, 3, 4, 5};
    System.out.println("Test 2: " + solution.longestConsecutive(nums2)); // 6
    
    // 测试用例3:空数组
    int[] nums3 = {};
    System.out.println("Test 3: " + solution.longestConsecutive(nums3)); // 0
    
    // 测试用例4:单个元素
    int[] nums4 = {5};
    System.out.println("Test 4: " + solution.longestConsecutive(nums4)); // 1
    
    // 测试用例5:多个连续序列
    int[] nums5 = {10, 20, 30, 11, 12, 13};
    System.out.println("Test 5: " + solution.longestConsecutive(nums5)); // 4
    
    // 测试用例6:负数序列
    int[] nums6 = {-5, -4, -3, 0, 1};
    System.out.println("Test 6: " + solution.longestConsecutive(nums6)); // 3
}

关键点

  1. 起点识别
    通过检查 num-1 是否在集合中,确保每个连续序列只被处理一次

  2. 去重处理
    使用 HashSet 自动处理重复元素,避免重复计数

  3. 时间复杂度保证

    • 每个元素最多访问两次(起点识别 + 向后扩展)
    • 整体时间复杂度严格 O(n)
  4. 空间复杂度优化

    • 相比排序法(O(n log n) 时间复杂度),此解法满足 O(n) 时间复杂度要求
    • 空间复杂度 O(n) 是必要开销

扩展

  • 并查集解法
    可用并查集维护连续序列,但实现较复杂且空间开销更大
  • 排序解法
    先排序后遍历,时间复杂度 O(n log n),不满足题目要求
  • 流式处理
    适用于超大数据集(外排序+遍历),但时间复杂度仍为 O(n log n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值