128.最长连续序列

  1. 128.最长连续序列
    1. 128.1 题目
    2. 128.2 题解
      1. 方法一:哈希集合法
        1. 思路
        2. 复杂度分析
        3. 代码
    3. 128.3 代码
    4. 128.4 运行结果

128.最长连续序列


128.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

128.2 题解

方法一:哈希集合法

思路

题目要求 O(n) 时间复杂度,排序肯定不行(至少 O(n log n))。关键在于:如何快速判断一个数是否在数组中?

用 HashSet!它可以 O(1) 查询,还能自动去重。

核心技巧:只从序列的起点开始计数。怎么判断一个数是不是起点?如果 x-1 不在集合中,那 x 就是某个连续序列的起点。

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

  • 100 是起点(99不存在),向后找:100存在,101不存在,长度1
  • 4 不是起点(3存在),跳过
  • 200 是起点(199不存在),长度1
  • 1 是起点(0不存在),向后找:1,2,3,4都存在,5不存在,长度4 ← 最大

这样每个数最多被访问两次(一次判断是否起点,一次被某个起点向后遍历时访问),时间复杂度 O(n)。

复杂度分析

  • 时间复杂度:O(n),每个元素最多被访问两次
  • 空间复杂度:O(n),HashSet 存储所有元素

代码

// 方法一:哈希集合法
// 核心思路:使用哈希集合存储所有数字,然后遍历集合寻找连续序列的起点
// 重点是找起点,往左边找如果有,那说明不是起点,直接跳过此次循环。
// 时间复杂度:O(n),每个元素最多被访问两次
// 空间复杂度:O(n),需要存储所有数字到哈希集合
// 优点:满足O(n)时间复杂度要求,实现相对高效
// 缺点:需要额外的空间存储哈希集合
static int LongestConsecutive1(int[] nums)
{
    if (nums == null || nums.Length == 0)
        return 0;

    // 简化:直接用数组初始化哈希集合,自动去重
    HashSet<int> set = new HashSet<int>(nums);
    int result = 0; // 初始值设为0更合理

    foreach (var item in set)
    {
        // 只有当前数字是序列起点(前一个数不存在),才统计
        if (set.Contains(item - 1))
            continue;

        int tempResult = 1;
        int val = item;
        // 往后找连续数字,统计长度
        while (set.Contains(++val))
        {
            tempResult++;
        }

        result = Math.Max(result, tempResult);
    }

    return result;
}

128.3 代码

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        #region 题目

        // 给定一个未排序的整数数组 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

        #endregion

        #region 测试

        // 示例 1
        int[] nums1 = { 100, 4, 200, 1, 3, 2 };
        int result11 = LongestConsecutive1(nums1);
        Console.WriteLine($"示例1 方法1 输出:{result11}");

        // 示例 2
        int[] nums2 = { 0, 3, 7, 2, 5, 8, 4, 6, 0, 1 };
        int result21 = LongestConsecutive1(nums2);
        Console.WriteLine($"示例2 方法1 输出:{result21}");

        // 示例 3
        int[] nums3 = { 1, 0, 1, 2 };
        int result31 = LongestConsecutive1(nums3);
        Console.WriteLine($"示例3 方法1 输出:{result31}");

        #endregion
    }

    #region 答案

    // 方法一:哈希集合法
    // 核心思路:使用哈希集合存储所有数字,然后遍历集合寻找连续序列的起点
    // 重点是找起点,往左边找如果有,那说明不是起点,直接跳过此次循环。
    // 时间复杂度:O(n),每个元素最多被访问两次
    // 空间复杂度:O(n),需要存储所有数字到哈希集合
    // 优点:满足O(n)时间复杂度要求,实现相对高效
    // 缺点:需要额外的空间存储哈希集合
    static int LongestConsecutive1(int[] nums)
    {
        if (nums == null || nums.Length == 0)
            return 0;

        // 简化:直接用数组初始化哈希集合,自动去重
        HashSet<int> set = new HashSet<int>(nums);
        int result = 0; // 初始值设为0更合理

        foreach (var item in set)
        {
            // 只有当前数字是序列起点(前一个数不存在),才统计
            if (set.Contains(item - 1))
                continue;

            int tempResult = 1;
            int val = item;
            // 往后找连续数字,统计长度
            while (set.Contains(++val))
            {
                tempResult++;
            }

            result = Math.Max(result, tempResult);
        }

        return result;
    }

    #endregion
}

128.4 运行结果

示例1 方法1 输出:4
示例2 方法1 输出:9
示例3 方法1 输出:3


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏