算法题 法算day3 lief 2025-11-17 2025-11-21 最长序列 问题描述 给定一个未排序的整数数组 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
tip
特性
HashSet
HashMap<Integer, Integer>
本质
只存“值”的集合
存“键值对”的映射表
泛型参数
(元素类型)
<K, V>(键类型,值类型)
能否重复
元素不能重复
键不能重复,值可以重复
查询方式
contains(value) 判断值是否存在
get(key) 用键取值
常用方法
add(e)、remove(e)、contains(e)
put(k,v)、get(k)、remove(k)
java版 方法一:先把所有数字放进“快速查找表”HashSet,然后只从每个“序列开头”往后数,数完更新最长值,保证每个数字最多被看两遍,时间复杂度就是 O(n)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.util.HashSet; import java.util.Set; public class Solution { public int longestConsecutive(int[] nums) { // 如果数组是空的,直接返回 0,啥也不用干 if (nums == null || nums.length == 0) { return 0; } // 1. 先把所有数字“丢进”一个 HashSet,相当于建立一个“快速查找表” Set<Integer> numSet = new HashSet<>(); for (int num : nums) { numSet.add(num); } int maxLength = 0; // 用来记录全局最长连续序列的长度 // 2. 开始遍历数组 for (int num : nums) { // 2.1 只有当“num-1”不在集合里时,num 才是一个连续序列的“开头” if (!numSet.contains(num - 1)) { int currentNum = num; // 从当前这个“开头”出发 int currentLength = 1; // 目前这个序列长度先算 1(只有自己) // 2.2 不断看“下一个数字”在不在集合里,如果在就继续往后数 while (numSet.contains(currentNum + 1)) { currentNum++; // 挪到下一个数字 currentLength++; // 序列长度 +1 } // 2.3 这一整条序列数完了,更新全局最大值 maxLength = Math.max(maxLength, currentLength); } } // 3. 最后把最长长度返回即可 return maxLength; } }
✅ 说明:
时间复杂度 建集合:for num in nums 一次遍历,O(n)。 再遍历数组:看似两层循环,但每个数字最多被“往后数”一次; 一旦某个数字被当作序列内部元素(非起点)时,根本不会进入内层 while。 所以总工作量 ≤ 2n,仍属 O(n)。
空间复杂度 额外开了一个集合 num_set,最坏存下所有元素,大小 n,因此 O(n)。 总结: 算法只多占一份“哈希表”内存,却换来线性时间,是典型“空间换时间”的套路。
python版 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 from typing import List class Solution: def longestConsecutive(self, nums: List[int]) -> int: # 1. 空数组直接返回 0 if not nums: return 0 # 2. 把所有数字放进集合,方便 O(1) 查找 num_set = set(nums) max_length = 0 # 全局最长连续序列长度 # 3. 遍历每个数字 for num in nums: # 3.1 只有当 num-1 不在集合里时,num 才是一个序列的“开头” if num - 1 not in num_set: current_num = num # 从当前数字开始往后数 current_length = 1 # 目前序列长度至少为 1(自己) # 3.2 不断看“下一个数字”是否存在 while current_num + 1 in num_set: current_num += 1 # 挪到下一个数字 current_length += 1 # 长度 +1 # 3.3 更新全局最大值 max_length = max(max_length, current_length) # 4. 返回最长长度 return max_length # 简单测试 if __name__ == "__main__": print(Solution().longestConsecutive([100, 4, 200, 1, 3, 2])) # 输出 4 print(Solution().longestConsecutive([0, 3, 7, 2, 5, 8, 4, 6, 0, 1])) # 输出 9