算法练习-最长连续序列
原题连接:128. 最长连续序列 - 力扣(LeetCode)
问题描述
给定一个未排序的整数数组 nums
,你需要找出数字连续的最长序列的长度。注意:这个序列不要求元素在原数组中连续,但数字必须是连续的整数(例如,[1, 2, 3, 4])。要求算法的时间复杂度为 O(n),这意味着你不能使用排序(因为排序通常是 O(n log n)),必须使用更高效的方法。
示例分析
-
示例1:
nums = [100, 4, 200, 1, 3, 2]
-
最长连续序列是 [1, 2, 3, 4],长度为 4。
-
-
示例2:
nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
-
最长连续序列是 [0, 1, 2, 3, 4, 5, 6, 7, 8],长度为 9(注意重复的 0 只算一次)。
-
-
示例3:
nums = [1, 0, 1, 2]
-
最长连续序列是 [0, 1, 2],长度为 3(重复元素不影响序列长度)。
-
方法思路:使用哈希集合
为了达到 O(n) 的时间复杂度,我们使用一个哈希集合(HashSet)来存储所有数字。哈希集合允许我们以 O(1) 的时间检查某个数字是否存在。基本思路是:
-
将数组转换为集合:这样可以去重,并快速查找数字。
-
查找序列起点:对于每个数字,如果它的前一个数(即
num - 1
)不在集合中,那么它可能是一个连续序列的起点。 -
扩展序列:从起点开始,逐个检查后一个数(即
num + 1
、num + 2
等)是否在集合中,并计算序列长度。 -
更新最大长度:在遍历过程中,记录遇到的最长序列长度。
为什么这样是 O(n)?因为每个数字最多被访问两次(一次在遍历中,一次在扩展序列时),所以总时间复杂度是 O(n)。
代码实现(Python)
以下是 Python 代码,逐行解释:
def longestConsecutive(nums):# 如果数组为空,直接返回0if 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 = numcurrent_length = 1# 扩展序列:检查后一个数是否在集合中while current_num + 1 in num_set:current_num += 1current_length += 1# 更新最大长度max_length = max(max_length, current_length)return max_length
代码解释:
-
第2-4行:处理空数组的情况,直接返回0。
-
第6行:将数组
nums
转换为集合num_set
,这样可以去重并实现 O(1) 的查找。 -
第7行:初始化
max_length
为0,用于记录最长序列长度。 -
第9行:遍历集合中的每个数字(注意:遍历集合而不是原数组,以避免重复处理)。
-
第11-12行:检查当前数字
num
是否是序列的起点。如果num - 1
不在集合中,说明num
是一个起点。 -
第13-18行:从起点开始,通过
while
循环扩展序列,检查current_num + 1
是否在集合中,并增加当前序列长度current_length
。 -
第20行:更新最大长度
max_length
。 -
第22行:返回最终结果。
复杂度分析
-
时间复杂度:O(n)。虽然有一个嵌套的
while
循环,但每个数字最多被访问两次(一次在外部循环,一次在内部循环),所以总操作次数是线性的。 -
空间复杂度:O(n)。因为使用了一个集合来存储数字,最坏情况下集合大小为 n。
示例演练
以示例1 nums = [100, 4, 200, 1, 3, 2]
为例:
-
集合为
{100, 4, 200, 1, 3, 2}
。 -
遍历集合:
-
数字100:100-99=1不在集合中,所以是起点。扩展序列:101不在集合中,序列长度1。
-
数字4:4-3=1在集合中?是的(3在集合中),所以不是起点,跳过。
-
数字200:200-199=1不在集合中,所以是起点。扩展序列:201不在集合中,序列长度1。
-
数字1:1-0=0不在集合中,所以是起点。扩展序列:2在集合中,3在集合中,4在集合中,5不在集合中。序列长度4。
-
数字3和2:已经被处理过(因为不是起点),跳过。
-
-
最大长度为4。
注意事项
-
重复元素:集合自动去重,所以重复元素不会影响结果。
-
负数和大数:算法处理负数和大数没有问题,因为集合查找是 O(1)。
-
边界条件:如果数组为空,直接返回0。