【每日练题-leecode128. 最长连续序列】

128. 最长连续序列

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

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109

这个问题可以通过使用哈希表来解决。我们可以利用哈希表来记录每个数字是否出现过,以及它之前和之后的数字是否出现过。具体步骤如下:

  1. 将数组中的所有数字放入哈希表中,同时记录每个数字的连续序列长度。
  2. 对数组进行排序,这样我们可以更容易地找到连续的数字。
  3. 遍历排序后的数组,对于每个数字,检查它之前和之后的数字是否在哈希表中出现过。如果是,更新当前数字的连续序列长度。
  4. 维护一个变量来记录遍历过程中发现的最长连续序列长度。

代码实现:

class Solution:
    def longestConsecutive(self, nums):
        if not nums:
            return 0
        
        num_set = set(nums)
        max_length = 0
        
        for num in num_set:
            if num - 1 not in num_set:
                # 当前数字是连续序列的开始
                current_num = num
                current_length = 1
                
                while current_num + 1 in num_set:
                    current_num += 1
                    current_length += 1
                
                max_length = max(max_length, current_length)
        
        return max_length

# 示例
solution = Solution()
print(solution.longestConsecutive([100, 4, 200, 1, 3, 2])) # 输出 4
print(solution.longestConsecutive([0, 3, 7, 2, 5, 8, 4, 6, 0, 1])) # 输出 9

这段代码首先定义了一个Solution类,其中包含了longestConsecutive方法来解决这个问题。我们使用了一个集合num_set来存储输入数组中的所有数字,以利用集合的快速查找特性。然后,我们遍历这个集合,对于每个数字,检查它是否是连续序列的开始。如果是,我们就尝试找到这个连续序列的结束,并更新最长连续序列的长度。最后,我们返回找到的最长连续序列的长度。

这段代码是一个算法,用于找出一个未排序的整数数组中最长的连续序列的长度。这里的“连续序列”指的是数字是连续的,但它们在数组中的位置不需要是连续的。

让我们逐步分析代码:

  1. 类定义

    • class Solution: 定义了一个名为Solution的类,这个类将包含解决问题的方法。
  2. 方法定义

    • def longestConsecutive(self, nums): 定义了一个方法longestConsecutive,它接收一个数组nums作为参数。
  3. 输入检查

    • if not nums: return 0 如果数组为空,直接返回0,因为没有连续序列。
  4. 创建集合

    • num_set = set(nums) 将数组nums转换为一个集合num_set,这样可以快速检查某个数字是否存在。
  5. 初始化最长序列长度

    • max_length = 0 初始化一个变量max_length来存储最长连续序列的长度。
  6. 遍历集合

    • for num in num_set: 遍历集合num_set中的每个数字。
  7. 检查序列开始

    • if num - 1 not in num_set: 检查当前数字num减1是否不在集合中,如果是,则说明num可能是一个连续序列的开始。
  8. 计算连续序列长度

    • current_num = num 设置当前检查的数字为num
    • current_length = 1 初始化当前连续序列的长度为1。
    • while current_num + 1 in num_set: 使用一个循环,只要current_num + 1在集合中,就继续增加current_num的值,同时增加current_length
  9. 更新最长序列长度

    • max_length = max(max_length, current_length) 每次循环后,比较并更新max_length为当前找到的最长序列长度和之前记录的最长序列长度中的较大值。
  10. 返回结果

    • return max_length 在遍历完所有数字后,返回记录的最长连续序列长度。

最后,代码中有两个print语句用于测试算法:

  • print(solution.longestConsecutive([100, 4, 200, 1, 3, 2])) 测试用例1,期望输出是4。
  • print(solution.longestConsecutive([0, 3, 7, 2, 5, 8, 4, 6, 0, 1])) 测试用例2,期望输出是9。

这个算法的时间复杂度是O(n),因为它只需要遍历一次集合中的所有数字,并且每次检查和更新操作都是常数时间的。

这段代码的空间复杂度和时间复杂度分析如下:

时间复杂度

  1. 将数组转换为集合:这一步的时间复杂度是O(n),其中n是数组nums的长度。
  2. 遍历集合中的每个元素:这一步的时间复杂度也是O(n)。
  3. 在集合中查找元素:对于每个元素,我们最多执行两次查找操作(检查num - 1num + 1是否存在),查找操作的平均时间复杂度是O(1)。
  4. 连续序列的增长:对于每个连续序列,我们最多执行n次循环,最坏情况下,这将导致O(n)的时间复杂度。
  5. 即使考虑while循环,总的迭代次数也不会超过数组的长度。

综合考虑,时间复杂度主要由遍历集合和查找操作决定,因此整体时间复杂度是O(n)。

空间复杂度

  1. 创建集合:集合num_set存储了数组nums的所有元素,因此空间复杂度是O(n)。
  2. 变量存储max_lengthcurrent_length等变量占用的内存空间相对于n来说是常数级别的。
  3. 主要由存储集合num_set所需的空间决定。

因此,空间复杂度主要由集合num_set决定,整体空间复杂度是O(n)。

这里的n是数组nums的长度。这个算法在最坏情况下的时间复杂度和空间复杂度都是线性的,符合题目要求的O(n)时间复杂度。然而,实际性能可能会因为输入数据的特性而有所不同,例如,如果输入数组已经排序或者包含大量重复元素,算法的效率可能会更高。

另外在代码中,while循环是用来扩展当前连续序列的。在最坏的情况下,如果数组中的数字已经排序,并且形成了一个最长的连续序列,那么每次循环都将检查序列中的下一个数字,直到序列结束。这意味着while循环可能会执行与连续序列长度相同次数的操作。

假设最长的连续序列包含k个数字,那么while循环将执行k-1次(因为序列的第一个数字在进入循环之前已经被计数了)。因此,对于每个连续序列,我们可能会有O(k)的时间复杂度。

然而,由于我们只对每个数字执行一次这样的while循环,并且所有连续序列的总长度不会超过n(数组的长度),因此总的时间复杂度仍然是O(n)。这是因为即使有多个连续序列,它们加起来的总长度也不会超过数组的长度。

关于空间复杂度,while循环不占用额外的空间,因为它只是用来更新计数器和检查集合中的元素,所以空间复杂度仍然是O(n),由存储集合num_set所需的空间决定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值