题目描述
题目链接:128. 最长连续序列 - 力扣(LeetCode)
定一个未排序的整数数组 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,2,3,4 这样,每个数比前一个数大1的序列。注意:
-
不需要在数组中是连续的(位置可以乱)
-
数字可以重复,但重复的不计入长度
-
比如
[1,2,2,3]的最长连续序列是[1,2,3],长度是3
为什么不能直接排序?
排序的时间复杂度是O(nlogn),题目要求O(n),所以我们需要想别的办法。
解题思路
核心思想:用HashSet实现O(1)查找
如果我们能快速知道一个数字是否存在,那么找连续序列就简单了。HashSet的查找时间复杂度是O(1),正好符合要求。
关键优化:只从序列的起点开始找
比如数组 [100,4,200,1,3,2]:
-
数字2:它前面有1,所以它不是起点(1,2,3,4这个序列应该从1开始找)
-
数字3:它前面有2,也不是起点
-
数字4:它前面有3,也不是起点
-
数字1:它前面没有0,所以它是起点!
这样我们只从起点开始找,避免了重复计算,保证了O(n)的时间复杂度。
代码实现(详细注释版)
java
class Solution {
public int longestConsecutive(int[] nums) {
// 步骤1:处理边界情况
// 如果数组为空或长度为0,直接返回0
if (nums == null || nums.length == 0) {
return 0;
}
// 步骤2:创建HashSet,将数组中的所有元素存入
// HashSet有两个作用:1.去重 2.提供O(1)的查找
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
set.add(nums[i]);
}
int longest = 0; // 记录最长连续序列的长度
// 步骤3:将set转换成数组,方便用传统for循环遍历
// 因为set不能直接用下标访问,所以先转成数组
Integer[] setArray = set.toArray(new Integer[0]);
// 步骤4:遍历每一个数字
for (int i = 0; i < setArray.length; i++) {
int num = setArray[i]; // 当前要处理的数字
// 步骤5:关键优化!只从连续序列的起点开始找
// 如果num-1存在,说明num不是起点,直接跳过
// 比如数字2,因为1存在,所以2不是起点
if (!set.contains(num - 1)) {
int currentNum = num; // 当前数字,用于往后查找
int currentLength = 1; // 当前连续序列的长度,初始为1
// 步骤6:往后找连续的数字
// 只要下一个数字存在,就一直找下去
while (set.contains(currentNum + 1)) {
currentNum++; // 数字加1
currentLength++; // 长度加1
}
// 步骤7:更新最长长度
// 如果当前找到的长度比之前记录的最长长度还大,就更新
if (currentLength > longest) {
longest = currentLength;
}
}
}
// 步骤8:返回最长长度
return longest;
}
}
代码执行过程演示
让我们用示例1来一步步看代码是如何执行的:
输入 :nums = [100, 4, 200, 1, 3, 2]
第1步:创建HashSet
java
setArray = [100, 4, 200, 1, 3, 2] // 转换成数组方便遍历
第2步:转换成数组
java
setArray = [100, 4, 200, 1, 3, 2] // 转换成数组方便遍历
第3步:遍历数组中的每个数字
处理第1个数字:100
-
检查99在set中吗? → 不在
-
所以100是起点
-
往后找101? → 不在set中
-
当前长度 = 1
-
longest = max(0, 1) = 1
处理第2个数字:4
-
检查3在set中吗? → 在(set中有3)
-
所以4不是起点,跳过
处理第3个数字:200
-
检查199在set中吗? → 不在
-
所以200是起点
-
往后找201? → 不在set中
-
当前长度 = 1
-
longest = max(1, 1) = 1
处理第4个数字:1(关键!)
-
检查0在set中吗? → 不在
-
所以1是起点
-
往后找2? → 在set中,长度=2,当前数字变成2
-
往后找3? → 在set中,长度=3,当前数字变成3
-
往后找4? → 在set中,长度=4,当前数字变成4
-
往后找5? → 不在set中,停止
-
当前长度 = 4
-
longest = max(1, 4) = 4
处理第5个数字:3
-
检查2在set中吗? → 在
-
不是起点,跳过
处理第6个数字:2
-
检查1在set中吗? → 在
-
不是起点,跳过
最终结果
java
longest = 4 // 最长连续序列 [1,2,3,4] 的长度
图解算法流程
java
原始数组:[100, 4, 200, 1, 3, 2]
放入Set:{100, 4, 200, 1, 3, 2}
遍历过程(只从起点开始找):
┌─────────┬────────────┬───────────────┬────────────┬─────────┐
│ 数字 │ 是否是起点 │ 向后查找 │ 当前长度 │ 最长长度 │
├─────────┼────────────┼───────────────┼────────────┼─────────┤
│ 100 │ 是(无99) │ 101? ✗ │ 1 │ 1 │
│ 4 │ 否(有3) │ 跳过 │ - │ 1 │
│ 200 │ 是(无199) │ 201? ✗ │ 1 │ 1 │
│ 1 │ 是(无0) │ 2→3→4? ✓ │ 4 │ 4 │
│ 3 │ 否(有2) │ 跳过 │ - │ 4 │
│ 2 │ 否(有1) │ 跳过 │ - │ 4 │
└─────────┴────────────┴───────────────┴────────────┴─────────┘
最终最长长度 = 4
总结
-
核心数据结构:HashSet,提供O(1)的查找时间
-
关键技巧:只从连续序列的起点开始查找
-
算法步骤:
-
去重:将所有数字存入HashSet
-
找起点:如果num-1不存在,则num是起点
-
向后延伸:一直找num+1、num+2...直到找不到
-
更新最大值
-
相关题目推荐
- 存在重复元素
- 存在重复元素 II
- 最长连续递增序列
- 最长和谐子序列
如果这篇文章对你有帮助,欢迎点赞、收藏、关注!
你的支持是我持续创作的动力!
有什么问题欢迎在评论区留言,我会尽力解答!