算法题:力扣 热题100道 中等难度128. 最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

bash 复制代码
示例 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)

不考虑时间复杂度,而且从物理逻辑想好写的

bash 复制代码
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²)

再优化一版,还是不行,说明缺少一个核心的逻辑

bash 复制代码
 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;
    }

官方题解:

核心思想:只从"连续序列的起点"开始往后数。

bash 复制代码
     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)!

这道题因为看似简单实际考验了小朋友们的智商,所以各大厂常考,我只能说这道题做筛选绝了

相关推荐
浅川.251 小时前
xtuoj 方程
算法
Swift社区1 小时前
LeetCode 441 - 排列硬币
算法·leetcode·职场和发展
TL滕1 小时前
从0开始学算法——第七天(快速排序算法练习)
笔记·学习·算法·排序算法
MicroTech20251 小时前
MLGO微算法科技 D-S融合算法技术发布,助力脑机接口迈向实用化
大数据·科技·算法
Q741_1471 小时前
C++ 栈 模拟 力扣 844. 比较含退格的字符串 题解 每日一题
c++·算法·leetcode·模拟·
CoderYanger1 小时前
动态规划算法-简单多状态dp问题:14.粉刷房子
开发语言·算法·leetcode·动态规划·1024程序员节
张张努力变强1 小时前
二叉树——精选题目,体验递归的暴力美学!
c语言·数据结构·算法
FMRbpm1 小时前
栈练习--------(LeetCode 739-每日温度)
数据结构·c++·算法·leetcode·新手入门
子一!!1 小时前
数据结构==二叉平衡树,AVL树 ===
数据结构·算法