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

编程达人挑战赛·第5期 10w+人浏览 190人参与

给定一个未排序的整数数组 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)!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_Octopus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值