在 LeetCode 的【LeetCode热题100】系列中,No.128 题——最长连续序列,是一个经典的问题。它考察了我们对数据结构的理解和算法的优化能力。这道题看似简单,但想要写出高效且优雅的代码,却需要深入思考。
问题场景重现
给定一个未排序的整数数组 nums,找出最长连续序列的长度。例如,给定 nums = [100, 4, 200, 1, 3, 2],最长连续序列是 [1, 2, 3, 4],长度为 4。
底层原理深度剖析
最直观的解法是暴力搜索:对于数组中的每个数字,都向上和向下搜索,直到找不到连续的数字为止。这种方法的时间复杂度是 O(n^2),当数组很大时,性能会非常差。
一个更高效的解法是使用哈希表。我们首先将数组中的所有数字放入哈希表中,然后对于数组中的每个数字,如果它在哈希表中存在,则从该数字开始,向上和向下搜索连续的数字,每找到一个连续的数字,就将其从哈希表中删除。这样可以避免重复搜索,并将时间复杂度降低到 O(n)。
为什么要用哈希表?因为哈希表的查找操作是 O(1) 的时间复杂度,可以快速判断一个数字是否存在于数组中。对比之下,如果使用排序后的数组进行二分查找,时间复杂度是 O(n log n)。
具体的代码/配置解决方案
下面是用 Python 实现的哈希表解法:
def longestConsecutive(nums):
num_set = set(nums)
longest_streak = 0
for num in nums:
if num - 1 not in num_set: # 确保是从序列的起点开始
current_num = num
current_streak = 1
while current_num + 1 in num_set:
current_num += 1
current_streak += 1
longest_streak = max(longest_streak, current_streak)
return longest_streak
这个算法的关键在于 if num - 1 not in num_set: 这行代码。它保证了我们只从一个连续序列的起点开始搜索,避免了重复计算,从而将时间复杂度降低到 O(n)。
实战避坑经验总结
- 去重:如果数组中存在重复的数字,需要先进行去重,否则可能会导致结果错误。可以使用
set()方法进行去重。 - 边界条件:需要考虑数组为空的情况,此时最长连续序列的长度为 0。
- 空间复杂度:哈希表解法需要额外的空间来存储数组中的数字,空间复杂度是 O(n)。在某些情况下,如果对空间复杂度有严格的要求,可以考虑使用其他算法,例如排序后进行线性扫描,但时间复杂度会增加到 O(n log n)。
- 数据量大时优化:当数据量非常大时,哈希表的性能可能会受到影响。可以考虑使用 Bloom Filter 来进一步优化。Bloom Filter 是一种概率型数据结构,可以快速判断一个元素是否存在于集合中,但可能会有一定的误判率。在 Nginx 这种高并发的服务器中,Bloom Filter 也常用于缓存穿透的防护,通过快速判断请求的 key 是否存在于缓存中,来避免大量请求直接打到数据库上,导致数据库压力过大。同时,合理设置 Nginx 的 worker 进程数、调整 worker 连接数,也能有效提升整体性能。
在实际工作中,需要根据具体的场景和需求,选择合适的算法和数据结构。例如,如果对时间复杂度有严格的要求,但对空间复杂度没有限制,则可以选择哈希表解法。如果对空间复杂度有严格的要求,则可以选择排序后进行线性扫描。理解各种算法和数据结构的优缺点,才能在实际工作中做出正确的决策。
【LeetCode热题100】中最长连续序列这道题,不仅考察了算法和数据结构,也考察了我们分析问题、解决问题的能力。通过深入理解问题的本质,并选择合适的算法和数据结构,我们可以写出高效且优雅的代码,提升程序的性能。
冠军资讯
不想写注释