当前位置: 首页 > news >正文

力扣刷题#11:LeetCode128最长连续序列_刷题笔记

力扣刷题#11:LeetCode128最长连续序列_刷题笔记

题目描述

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

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

示例:

输入:nums = [100, 4, 200, 1, 3, 2]
输出:4
解释:最长连续序列是 [1, 2, 3, 4],长度为 4。

Step 1:先想一个直觉解法(排序 + 双指针)

最朴素的想法:

排序 → 相邻元素比较,遇到不连续的就重置计数
sort(nums.begin(), nums.end());
int ans = 1, cur = 1;
for (int i = 1; i < n; i++) {if (nums[i] == nums[i - 1]) continue;      // 跳过重复if (nums[i] == nums[i - 1] + 1) cur++;      // 连续else { ans = max(ans, cur); cur = 1; }      // 断了
}
复杂度 说明
时间复杂度 O(n log n) 排序是瓶颈
空间复杂度 O(1) 原地排序

题目要求 O(n),所以排序不行。那怎么去掉 log n 的排序开销?


Step 2:用哈希集合存储所有元素

把数组元素放进 unordered_set,就可以 O(1) 查值了。

unordered_set<int> s(nums.begin(), nums.end());

简单粗暴的想法(会超时)

对每个数,往后查连续数字:

for (int num : nums) {int t = num, len = 1;while (s.count(++t)) len++;ans = max(ans, len);
}

问题:大量重复遍历!

nums = [1, 2, 3, 4]
从 1 出发:查到 2, 3, 4   ✅
从 2 出发:查到 3, 4       💥 重复
从 3 出发:查到 4          💥 重复
从 4 出发:查不到          ✅

最坏情况 O(n²) —— 这就是上一版超时的原因。


Step 3:关键优化——只从序列起点开始查

什么数是序列的起点?

一个数字是序列的起点,当且仅当 num - 1 不在 set 中。

[1, 2, 3, 4] 中:1: 0 不在 set → ✅ 起点2: 1 在 set   → ❌ 不是起点3: 2 在 set   → ❌ 不是起点4: 3 在 set   → ❌ 不是起点

只有从起点出发,才能查到完整序列;从中间出发查到的都是 「已经被走过的路」

加上起点判断后,每个元素最多被遍历一次

修正后的逻辑:

for (const int& num : s) {                    // 遍历 set(去重)if (s.count(num - 1) == 0) {               // 是起点int t = num, cns = 1;while (s.count(++t)) cns++;            // 往后延展ans = max(ans, cns);                   // 出循环再 max}
}

为什么复杂度是 O(n)?

  • 每个数只有作为起点时才进入 while 循环
  • while 循环里遍历的每个数不会被第二个起点再遍历到
  • 所有 while 累计总步数 ≤ 数组长度

踩坑记录

❌ Bug 1:变量名写混

unordered_set<int> s;
s.insert(nums[i]);   // ✅ 正确
// set.insert(nums[i]);  // ❌ s 写成了 set

❌ Bug 2:cns 忘记声明类型

cns = 1;   // ❌ 编译错误
int cns = 1;  // ✅

❌ Bug 3:while 结束后没更新 m

while (...) { m = max(m, ++cns); }   // 🔴 每次都 max,浪费
while (...) { cns++; }               // 只自增
m = max(m, cns);                     // 循环结束再 max

❌ Bug 4:重复元素导致超时

遍历 nums 而不是 set 会导致相同值的元素反复触发相同的 while 循环,最坏情况 O(n²)。

修复:遍历 set 而非 nums


最终 AC 代码

class Solution {
public:int longestConsecutive(vector<int>& nums) {if (nums.empty()) return 0;unordered_set<int> s(nums.begin(), nums.end());int ans = 0;for (const int& num : s) {if (s.count(num - 1) == 0) {          // 是序列起点int t = num, cns = 1;while (s.count(++t)) cns++;       // 往后延展ans = max(ans, cns);              // 更新最大值}}return ans;}
};
复杂度 说明
时间复杂度 O(n) 每个元素最多进入 while 一次
空间复杂度 O(n) 哈希集合存储全部元素

附:关于力扣跑分的说明

这道题我第一次跑 91ms,优化后反而跑了 111ms——这是力扣服务器负载波动,不是代码的问题。

影响因素 说明
服务器负载 忙时慢、闲时快
测试用例随机化 不同次可能跑不同子集
计时精度 毫秒级计时,波动几十 ms 很正常

真正该关注的不是击败百分比,而是复杂度分析。99ms 还是 111ms 对你面试没有任何区别,继续刷下一题就行。


本文档由 AI 辅助生成,作者提供问题和思路,综合获得以上内容。

http://www.gsyq.cn/news/1488828.html

相关文章:

  • 氛围感满分!在厦门,拍一套治愈一辈子的海景婚纱照 - 奔跑123
  • 国产PCB厂家综合实力排行,这5家值得关注
  • 系统架构设计师-计算机系统组成与层次化存储体系深度解析
  • 如何免费使用Duplicity存档编辑器:缺氧游戏存档修改完整指南
  • Markdown 阅读器全平台精选(只看.md 文件 / 兼顾读写分开推荐)
  • 广州番禺上门回收黄金奢侈品,价格公道服务好速度快 - 花生花生1
  • 2026年 3-(1,4-丁炔二醇)-磺丙基醚单钠盐(丁醚嗡盐)厂家推荐:电镀镍中间体核心原料,高纯度与稳定性深度解析 - 品牌发掘
  • Java数据结构——二叉树(Binary Tree)详解
  • 蓝桥杯Java组B类选手,我是如何用‘笨办法’刷题拿到省一的?
  • 如何用ComfyUI-MimicMotionWrapper快速实现视频动作迁移:3步完成AI动作复刻
  • 国产PCB厂家综合实力排行,这5家真值得看
  • 2026年东莞波珠螺丝/定位珠螺丝/弹簧碰珠螺丝厂家推荐:高精度与耐用性并存的优质品牌深度评测 - 品牌发掘
  • CAN-FD比特率切换与发射延迟补偿实战:基于LPC5500的配置详解
  • 别再只盯着准确率了!用sklearn的Brier Score和Log Loss,手把手教你评估分类模型的预测概率到底靠不靠谱
  • 3步解锁AMD GPU大模型部署:Ollama-for-amd终极配置指南
  • 跨语言手写检索的轻量级双编码器框架设计与优化
  • 5分钟掌握SPT-AKI Profile Editor:逃离塔科夫离线版终极存档修改器
  • NXP Kinetis触摸库实战:从环境搭建到FreeMASTER高级调试
  • 轻量级跨语言手写检索技术解析与应用实践
  • Origin 2018保姆级安装教程:从下载到配置,手把手教你搞定科研绘图第一步
  • 深入解析 Leaflet 地图精度与高德地图集成实践
  • Verilog新手避坑指南:从4位全加器到8位乘法器,手把手教你搞定仿真和RTL视图
  • LiteEmbed:CLIP模型的轻量级适配框架优化罕见类别识别
  • HarmonyOS 6.1 开发者盛宴|《灵犀厨房》实战(三十):【社区分享】本地社区功能——让菜谱从“独享”走向“共享”
  • 炉石传说HsMod:解锁55项隐藏功能的游戏体验革命
  • 3步解锁AMD Ryzen处理器隐藏性能:SMU Debug Tool新手完全指南
  • 从原理看 Arthas 为何比 IDEA Profiler 更“懂”你的代码
  • Vue i18n动态加载进阶:结合Pinia/Vuex管理多语言状态与接口缓存策略
  • 哔咔漫画下载器终极指南:快速搭建个人离线漫画库的完整方案
  • LangGraph+ElevenLabs构建可控AI播客生产流水线