LeetCode128-最长连续序列
题目
给定一个未排序的整数数组 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
分析
1. 初步思考与暴力解法
最直观的想法是,对于数组中的每一个数 x,我们都去尝试寻找 x+1, x+2, x+3, … 是否存在于数组中,直到找不到为止,以此来确定以 x 开头的连续序列的长度。然后我们遍历所有数字,找出最长的那个长度。
这个方法需要两层循环:外层循环遍历每个数字 x,内层循环则去数组中查找 x+1, x+2 等。在未排序的数组中查找一个元素的时间复杂度是 O(n),因此总的时间复杂度会是 O(n^2) 甚至 O(n^3),这不满足题目 O(n) 的要求。
2. 排序法
一个改进的思路是先对数组进行排序。
思路:
- 对原数组
nums进行排序。 - 遍历排序后的数组,用一个变量
currentStreak记录当前连续序列的长度,用另一个变量longestStreak记录全局最长的连续序列长度。 - 如果当前数字比前一个数字大 1,则
currentStreak加 1。 - 如果当前数字与前一个数字相等,说明是重复数字,跳过即可,不影响连续性。
- 如果当前数字比前一个数字大超过 1,说明连续序列中断了,重置
currentStreak为 1。 - 每次更新
currentStreak后,都用它来更新longestStreak。
- 对原数组
复杂度分析:
- 时间复杂度:
O(n \log n)。主要瓶颈在于排序。 - 空间复杂度:
O(1)或O(\log n),取决于排序算法内部使用的空间。
- 时间复杂度:
结论: 这个方法虽然比暴力法好,但时间复杂度仍然不满足题目要求的 O(n)。
3. 最优解法:哈希集合(HashSet)
为了达到 O(n) 的时间复杂度,我们需要一种能在 O(1) 时间内判断一个数是否存在的方法。这自然让我们想到了哈希表(在 Java 中是 HashSet)。
核心思想:
我们希望对一个连续序列,只在其起点(序列中最小的数)进行一次完整的遍历和计数。这样可以避免对序列中的其他数字(如 2, 3, 4)进行重复的计数工作。如何判断一个数是序列的起点?
一个数num如果是连续序列的起点,那么num - 1这个数一定不存在于数组中。算法步骤:
- 预处理: 创建一个
HashSet,将数组nums中的所有数字都存入HashSet。这一步有两个目的:- 去重:
HashSet自动处理了重复的数字。 - 快速查找:提供了 O(1) 的平均时间复杂度的
contains方法。
- 去重:
- 遍历和计数: 遍历
HashSet中的每一个数字num(或者遍历原数组nums也可以)。 - 寻找起点: 对于当前的数字
num,检查set.contains(num - 1)是否为false。- 如果为
true,意味着num不是一个序列的起点(例如,对于序列[1, 2, 3, 4],当我们遍历到2时,因为1存在,所以2不是起点),我们直接跳过,不做任何处理。 - 如果为
false,意味着num是一个连续序列的起点。我们就从num开始,不断检查num + 1,num + 2, … 是否存在于HashSet中,并计数,直到序列中断。
- 如果为
- 更新最长长度: 在找到一个序列的完整长度后,与全局的最长长度
longestStreak进行比较并更新。 - 返回结果: 遍历完所有数字后,
longestStreak就是最终结果。
- 预处理: 创建一个
复杂度分析:
- 时间复杂度: O(n)。
- 将
n个数字添加到HashSet中需要 O(n) 的时间。 - 外层循环会执行
n次(最多,如果无重复数字)。 - 内层的
while循环看起来像是嵌套循环,但需要注意的是,while循环只会在一个数是序列起点时才会被执行。对于整个算法来说,每个数字最多只会被while循环访问一次(作为currentNum + 1)。因此,所有while循环的总执行次数加起来也是 O(n) 级别的。 - 总的时间复杂度是 O(n) + O(n) = O(n)。
- 将
- 空间复杂度: O(n)。我们需要一个
HashSet来存储数组中所有的不重复元素。
- 时间复杂度: O(n)。
结论: 此方法在时间和空间上都满足题目的要求,是本题的最优解。
答案
1 | import java.util.HashSet; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 技术博客!









