给定一个未排序的整数数组 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
1.这道题其实很有说法,看题目很简单,但是考察的知识点比较细,比较考验逻辑思考能力(就是尼玛难为人,给聪明人写的题)
1.数字去重
2.计数算最长连续数
3.时间复杂度O(n)
不考虑时间复杂度,而且从物理逻辑想好写的
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> sets = new HashSet<Integer>();
for(int num: nums){
sets.add(num);
}
int maxLength = 0;
for(int num :sets){
int currentLength = 1;
int i =1;
// 如果集合中包含当前数的后一个数,说明是连续的
if (sets.contains(num+i)){
++currentLength;
++i;
int j = 0;
while(j<sets.size()){
if(sets.contains(num+i)){
++currentLength;
i++;
} else {
break;
}
j++;
}
}
if(currentLength>maxLength){
maxLength= currentLength;
}
}
return maxLength;
}
}

时间复杂度为O(n²)
再优化一版,还是不行,说明缺少一个核心的逻辑
public static int longestConsecutive(int[] nums) {
Set<Integer> sets = new HashSet<Integer>();
for (int num : nums) {
sets.add(num);
}
int maxLength = 0;
for (int num : sets) {
int currentLength = 1;
int next = 1;
// 如果集合中包含当前数的后一个数,说明是连续的
while (sets.contains(num + next)) {
currentLength++;
next++;
}
if (currentLength > maxLength) {
maxLength = currentLength;
}
}
return maxLength;
}
官方题解:
核心思想:只从“连续序列的起点”开始往后数。
Set<Integer> sets = new HashSet<Integer>();
for (int num : nums) {
sets.add(num);
}
int maxLength = 0;
for (int num : sets) {
// 只有当num 是连续序列的起点时才开始统计
if(!sets.contains(num -1)){
int currentNum = num;
int currentLength = 1;
// 往后查找连续的数
while (sets.contains(currentNum+1)){
currentNum++;
currentLength++;
}
if (currentLength > maxLength){
maxLength = currentLength;
}
}
}
return maxLength;
假设你有一串连续的数字:
[10, 11, 12, 13]
这其实就是一个连续序列,长度是 4。
❌ 如果你不加 if (!set.contains(num - 1)):
你的程序会对每个数都尝试“往后数”:
看到 10 → 数:10,11,12,13 → 长度 4 ✅(有用)
看到 11 → 数:11,12,13 → 长度 3 ❌(重复!前面已经算过了)
看到 12 → 数:12,13 → 长度 2 ❌(又重复!)
看到 13 → 数:13 → 长度 1 ❌(完全没必要)
👉 同一个答案,算了 4 次!
如果这个序列有 1 万个数,你就白白多做了 差不多 5000 万次 的检查!
✅ 加上 if (!set.contains(num - 1)) 之后:
看到 10:检查 9 在不在?不在 → 说明 10 是开头 → 开始数 ✅
看到 11:检查 10 在不在?在! → 说明 11 不是开头 → 直接跳过!
看到 12:11 在 → 跳过!
看到 13:12 在 → 跳过!
✅ 只干一次活,就得到正确答案!
🌟 这句代码的“妙处”在哪?
它让程序“聪明地只从每段连续序列的最左边开始数”,绝不回头、绝不重复。
就像你要数一排连在一起的灯笼有多长:
聪明人:只从最左边那个开始往右数一次
不聪明的人:每个灯笼都当成起点数一遍(每次看到这样的话都感觉在欺负人)
if (!set.contains(num - 1)) 就是帮你找到“最左边那个灯笼”的开关!
为什么这能保证 O(n)?
每个数字最多被看两次:
在 for 循环里判断是不是起点(一次)
如果它是某段序列的一部分,可能在 while 里被访问一次
所有 while 加起来总共不会超过 n 次
所以总操作 ≈ 2n → O(n)!
这道题因为看似简单实际考验了小朋友们的智商,所以各大厂常考,我只能说这道题做筛选绝了
2061

被折叠的 条评论
为什么被折叠?



