代码训练LeetCode(5)最长连续序列

这篇具有很好参考价值的文章主要介绍了代码训练LeetCode(5)最长连续序列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

代码训练(5)LeetCode之最长连续序列

Author: Once Day Date: 2024年3月9日

漫漫长路,才刚刚开始…

全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客

参考文章:

  • 128. 最长连续序列 - 力扣(LeetCode)
  • 力扣 (LeetCode) 全球极客挚爱的技术成长平台
1. 原题

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

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

例如,nums = [4, 2, 4, 3, 5],其最长连续数字序列为2, 3, 4, 5,长度为4。

2. 分析

这个问题是在寻找最长连续序列的长度,但不要求这些序列在原数组中是连续的。要在 O(n) 时间复杂度内解决这个问题,我们可以利用哈希表(在 C 中通常使用散列表或字典类型的数据结构)。

解题思路如下:

  1. 使用哈希表来存储每个数字是否已经被访问过,这可以用来避免重复计算。
  2. 遍历数组中每个数字:
    • 如果该数字已在哈希表中,跳过它(因为它已经被计算过了)。
    • 如果该数字不在哈希表中,检查数字前后是否有连续的数字,即检查 num-1num+1 是否在数组中。
    • 如果有,继续向前后检测,直到找不到连续数字为止,同时更新哈希表。
    • 在此过程中,计算并更新最长连续序列的长度。

实例处理时,可以按照下面步骤:

  1. 创建一个哈希表 hash
  2. 遍历 nums,将每个元素作为键存入 hash,值为 false 表示该元素还未被访问。
  3. 再次遍历nums,对于每个元素,若其值为false,则进行以下操作:
    • 初始化当前长度为 1。
    • 向上查找 num + 1, num + 2, ...,直到找不到为止,每找到一个数,长度加 1。
    • 向下查找 num - 1, num - 2, ...,直到找不到为止,每找到一个数,长度加 1。
    • 更新结果为当前长度和已有结果的较大值。
  4. 返回最长连续序列的长度。

需要注意,其实这里把Hash表过于理想化了,实际上Hash表查询时间并非一定是O(1)。这个地方先存入nums的原因,是为了减少遍历次数,最差的情况下,是每个元素都查询一次,这样就是n次查询。

查询时判断是否n-1存在,就是判断当前这个值是否是一个序列的开始,这样对于长序列,也只有一个序列的开始值会完整查询所有值,这又是n次,所以整体复杂度维持在3n左右。

假设 nums = [100, 4, 200, 1, 3, 2]

  • 创建哈希表 hash,存入所有数字。
  • 遍历 nums,当我们到达 1 时,查找 0(不在 hash 中),然后查找 2(在 hash 中,更新长度),继续查找 34,到 5 时停止。序列长度为 4。
  • 以此类推,我们找到最长的序列长度为 4。

性能优化关键点:

  • 使用哈希表来达到平均 O(1) 时间复杂度的查询。
  • 只在数字为序列起点时(即 num-1 不在数组中时)进行序列长度计算,以避免重复计算。
3. 代码实现
3.1 排序实现
int cmp(const void *a, const void *b) 
{
    return *(int *)a < *(int *)b;
}

int longestConsecutive(int* nums, int numsSize) {
    int count, last, max_count = 0;

    if (numsSize == 0) {
        return 0;
    }

    qsort(nums, numsSize, sizeof(int), cmp);
    last = nums[0] - 1;
    count = 1;
    for(int i = 1; i < numsSize; i++) {
        if (last == nums[i]) {
            count++;
            last--;
        } else if (!(last + 1 == nums[i])) {
            
            if (count > max_count) {
                max_count = count;
            }
            count = 1;
            last = nums[i] - 1;
        }
    }
    
    if (count > max_count) {
        max_count = count;
    }

    return max_count;
}

这段代码实现了寻找最长连续序列的功能。主要逻辑如下:

  1. cmp函数是用于qsort的比较函数,比较两个整数的大小。
  2. longestConsecutive函数接收一个整数数组nums和数组大小numsSize,返回最长连续序列的长度。
  3. 首先判断数组是否为空,如果为空则返回0。
  4. 使用qsort函数对数组进行升序排序。
  5. 初始化变量last为第一个元素减1,count为1,表示当前连续序列的长度。
  6. 遍历排序后的数组,从第二个元素开始:
    • 如果当前元素与last相等,说明是重复元素,count加1,last减1。
    • 如果当前元素不等于last+1,说明连续序列中断,更新max_countcountmax_count的最大值,重置count为1,更新last为当前元素减1。
    • 如果当前元素等于last+1,说明连续序列继续,不需要进行操作。
  7. 遍历结束后,再次比较countmax_count,更新max_count
  8. 返回max_count,即最长连续序列的长度。

这个算法的时间复杂度是O(n log n),主要是排序的时间复杂度。空间复杂度是O(1)。在正常的情况下,排序做法其实也不错,比较节约内存

测试结果如下(仅供参考):

代码训练LeetCode(5)最长连续序列,CS小白之路,#  十年代码训练,# C语言,leetcode,算法,c语言

3.2 Hash表实现
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#define HASH_SIZE 65536

typedef struct hash_node {
    bool              flag;
    int               value;
    struct hash_node *next;
} hash_node;

hash_node *hash_table[HASH_SIZE];

static inline int hash(int value)
{
    return value & (HASH_SIZE - 1);
}

hash_node hash_table_cache[100000];
int       hash_table_cache_index = 0;

void hash_insert(int value)
{
    int        index    = hash(value);
    hash_node *node     = hash_table[index];

    if (node != NULL) {
        do {
            if (node->value == value) {
                return;
            }
            if (node->next == NULL) {
                break;
            }
            node = node->next;
        } while (1);
    }

    hash_node *new_node = &hash_table_cache[hash_table_cache_index++];
    new_node->value     = value;
    new_node->next      = NULL;
    new_node->flag      = false;
    if (node == NULL) {
        hash_table[index] = new_node;
    } else {
        node->next = new_node;
    }
}

hash_node *hash_find(int value)
{
    int        index = hash(value);
    hash_node *node  = hash_table[index];
    while (node != NULL) {
        if (node->value == value) {
            return node;
        }
        node = node->next;
    }
    return NULL;
}

bool is_visited(int value)
{
    hash_node *node = hash_find(value);
    if (!node->flag) {
        node->flag = true;
        return false;
    }
    return true;
}

void free_hash(void)
{
    memset(hash_table, 0, sizeof(hash_table));
    hash_table_cache_index = 0;
}

int longestConsecutive(int *nums, int numsSize)
{
    if (numsSize == 0 || numsSize > 100000) {
        return 0;
    }

    for (int i = 0; i < numsSize; ++i) {
        hash_insert(nums[i]);
    }

    int longestStreak = 0;

    for (int i = 0; i < numsSize; ++i) {
        if (hash_find(nums[i] - 1) == NULL) {
            if (is_visited(nums[i])) {
                continue;
            }
            int currentNum    = nums[i];
            int currentStreak = 1;

            while (hash_find(currentNum + 1)) {
                currentNum += 1;
                currentStreak += 1;
            }

            longestStreak = longestStreak > currentStreak ? longestStreak : currentStreak;
        }
    }

    free_hash();
    return longestStreak;
}

这段代码实现了一个哈希表,用于解决最长连续序列的问题。下面是对代码的简要解释:

  1. #define HASH_SIZE 65536:定义了哈希表的大小为65536。
  2. typedef struct hash_node { ... }:定义了哈希表节点的结构体,包含一个标志位flag、一个整数值value和指向下一个节点的指针next
  3. hash_node *hash_table[HASH_SIZE];:定义了一个哈希表数组,每个元素是指向哈希节点的指针。
  4. static inline int hash(int value):哈希函数,用于将整数值映射到哈希表的索引。这里使用了简单的按位与运算。
  5. hash_node hash_table_cache[100000];:定义了一个缓存数组,用于存储哈希节点,避免频繁的内存分配和释放。
  6. void hash_insert(int value):插入操作,将整数值插入到哈希表中。如果哈希表中已经存在该值,则不进行插入;否则,从缓存数组中取出一个新的节点,设置其值和指针,并将其插入到哈希表的对应位置。
  7. hash_node *hash_find(int value):查找操作,在哈希表中查找给定的整数值,并返回对应的节点指针。如果找不到,则返回NULL。
  8. bool is_visited(int value):判断一个整数值是否已经被访问过。如果对应的节点的flag为false,则将其设置为true并返回false,表示第一次访问;否则返回true,表示已经访问过。
  9. void free_hash(void):释放哈希表的内存,将哈希表数组清零,并将缓存数组的索引重置为0。
  10. int longestConsecutive(int *nums, int numsSize):求最长连续序列的长度的函数。首先将所有的整数值插入到哈希表中,然后遍历数组,对于每个整数值,如果它的前一个数不存在于哈希表中,则从该数开始向后搜索连续的数,直到无法继续为止,记录最长的连续序列长度。最后释放哈希表的内存并返回最长连续序列的长度。

这段代码使用哈希表来优化最长连续序列的查找过程,通过哈希表的快速插入和查找操作,可以在线性时间复杂度内解决问题。同时,使用缓存数组来避免频繁的内存分配和释放,提高了代码的性能。

下面是测试结果(仅供参考),可以看到执行效率很高,主要由Hash大小和元素分配缓存因素影响,减少无用的处理流程。

代码训练LeetCode(5)最长连续序列,CS小白之路,#  十年代码训练,# C语言,leetcode,算法,c语言

4. 总结

这个问题考察了对哈希表的使用,以及如何在不排序的情况下进行有效的搜索。这是一个对时间复杂度要求较高的问题,因此学习如何利用数据结构进行优化是非常重要的。要提升这方面的能力,建议多练习类似的问题,熟悉各种数据结构的性能特点,并学会根据问题的特点选择合适的数据结构。

对于哈希表的使用,需要注意的是如何处理冲突,以及如何设计一个好的哈希函数以减少冲突的发生。此外,在实际编码中,还需要考虑内存管理,确保所有分配的内存在不再使用时被正确释放,避免内存泄漏。







代码训练LeetCode(5)最长连续序列,CS小白之路,#  十年代码训练,# C语言,leetcode,算法,c语言

Once Day

也信美人终作土,不堪幽梦太匆匆......

如果这篇文章为您带来了帮助或启发,不妨点个赞👍和关注,再加上一个小小的收藏⭐!

(。◕‿◕。)感谢您的阅读与支持~~~文章来源地址https://www.toymoban.com/news/detail-842948.html

到了这里,关于代码训练LeetCode(5)最长连续序列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • leetcode做题笔记128. 最长连续序列

    给定一个未排序的整数数组  nums  ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为  O(n)   的算法解决此问题。 本题要求最长连续序列,可以将先将数组内数先排序一遍,再向后不断遍历数组比较得到最长连续序列,但

    2024年02月09日
    浏览(40)
  • 【LeetCode动态规划#14】子序列系列题(最长递增子序列、最长连续递增序列、最长重复子数组、最长公共子序列)

    力扣题目链接(opens new window) 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 示例 1: 输入:nums = [10,9,2,5,3,7,101,18] 输出

    2024年02月01日
    浏览(55)
  • LeetCode | C++ 动态规划——300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

    300题目链接 dp 数组定义 dp[i] 表示 i 之前包括 i 的以 nums[i]结尾 的最长递增子序列的长度 需要包含nums[i]结尾,不然在做递增比较的时候,就没有意义了。 递推公式 位置 i 的最长递增子序列 等于 j 从 0 到 i - 1各个位置的最长递增子序列 + 1 的 最大值 if (nums[i] nums[j]) dp[i] = ma

    2024年02月16日
    浏览(45)
  • ( 动态规划) 674. 最长连续递增序列 / 718. 最长重复子数组——【Leetcode每日一题】

    难度:简单 给定一个未经排序的整数数组,找到最长且 连续递增的子序列 ,并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r(l r) 确定,如果对于每个 l = i r ,都有 nums[i] nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。

    2024年02月05日
    浏览(49)
  • 【刷题之路】LeetCode 2389. 和有限的最长子序列

    原题连接: 2389. 和有限的最长子序列 题目描述: 给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。 返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。 子序列 是由一个数组删除某些元素(也可

    2023年04月16日
    浏览(30)
  • day55 最长递增子序列 最长连续递增子序列 最长重复子数组

    题目链接 300 最长递增子序列 题意 找到整数数组nums的最长严格递增子序列的长度(子序列并不改变原始的顺序,但是可以删除元素) 动态规划 动规五部曲 1)dp数组及下标i的含义 dp[i] 表示以nums[i]为结尾的最长递增子序列的长度 2)dp数组初始化 根据定义 长度至少是1  dp

    2024年04月11日
    浏览(59)
  • 力扣-哈希-最长连续序列

    给定一个未排序的整数数组  nums  ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为  O(n)  的算法解决此问题。 示例 1: **输入:**nums = [100,4,200,1,3,2] **输出:**4 **解释:**最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

    2024年02月10日
    浏览(31)
  • 算法刷题Day 52 最长递增子序列+最长连续递增子序列+最长重复子数组

    我自己想出来的方法,时间复杂度应该是 O(n2) 滑动窗口 连续的话,可以考虑用滑动窗口 动态规划 贪心算法

    2024年02月14日
    浏览(47)
  • 动态规划9:最长递增子序列、最长连续递增序列、最长重复子数组、最长公共子序列、不相交的线、最长子序和

    例题300: 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 确定dp数组和下标含义 dp[i]表示在第i个元素的最长子序列数

    2024年04月08日
    浏览(43)
  • 【Leecode】674. 最长连续递增序列

    Given an unsorted array of integers nums , return the length of the longest continuous increasing subsequence (i.e. subarray). The subsequence must be strictly increasing. A continuous increasing subsequence is defined by two indices l and r (l r) such that it is [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] and for each l = i r , nums[i] nums[i + 1] . E

    2024年02月07日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包