leetcode3731 逃课逮捕令:从 list 遍历 到 Set 精准锁头

逃课逮捕令:从 list 遍历 到 Set 精准锁头

大家好,我是一只被导师临时抓来当助教的研二狗。
今天老板出差,留给我一张皱成抹布样的签到表,以及一句杀人诛心的话:

“小李啊,这是本科班的课堂签到,1 到 50 号都在你手里了。把没来的揪出来,按学号排好发我。要是弄错一个,下周组会你替我做文献汇报。”

我打开签到表一看,血压飙得和服务器并发一样高。上面字迹歪歪扭扭:

[1, 25, 4, 18, 24, 9, 33, 15, 41, 50]

好家伙,签到顺序比我的论文提纲还乱,而且全班 50 号人,拢共只有 10 个签了到。最小号 1 和最大号 50 倒是在(这俩一个卷王一个学委,果然老实),其余的呢??我随手一刷朋友圈,37号刚晒了张五杀截图,配文是“教室哪有峡谷香”——我瞬间明白了,这货现在八成窝在床上和原神深渊使徒激情对线。

目标很明确,我现在需要做的就是:找出从 1 到 50 这个区间里,所有没出现在签到表上的学号,从小到大排好,一个不落,整整齐齐报给导师,让这些小兔崽子们接受命运——哦不,导师的审判。


黑历史 · 人工智障,逐个扫描

研一那会儿,我也曾被导师抓去当点名苦力。当时我还很天真,撸码常常堆循环,点名纯纯用爱发电——照着花名册,从 1 号开始,挨个在签到表里找。每查一个人都把整张表从头撸到尾,眼睛都快瞪成线性扫描仪了:“2号……不在。3号……也不在。4号——哦4号签了,下一个……”

def findMissingElements(nums: List[int]) -> List[int]:
    return [i for i in range(min(nums), max(nums) + 1) if i not in nums]

列表的 in 是 O(n) 线性扫描,外面再套一层 O(m) 的循环,合起来 O(n·m)。放到 OJ 上可能直接甩你一个 TLE。

这就好比在王者峡谷里不用小地图,纯靠走路挨个草丛探视野:“这个草丛有人吗?没有。下一个草丛呢?我再跑一趟……”等你探完上路,对面已经把主宰打了三遍,你家水晶炸得连渣都不剩。

最窒息的是,当我到宿舍抓人,37号正激情五杀,听到动静 Alt+Tab切桌面,转身挤出一个比bug还假的笑容:“学长你签到表有没有认真看?我名字签在背面——我回来拿个水杯!”


黑科技 · 哈希锁头,一秒查人

痛定思痛后,我掏出了计算机专业祖传秘方——哈希集合

原理很简单:把签到表上那十个幸运数字 [1,25,4,18,24,9,33,15,41,50] 一股脑塞进一个 set,取名 attended。这玩意儿就是个 O(1) 查找的超级花名册——从此查人不用遍历,直接问哈希:“这学号在吗?”,速度追平食堂阿姨打菜手速。

哈希点名,纯纯流水线作业:从 1 到 50 依次走过,每个学号对着 attended 问一句“ 在里面吗?”,不在的直接甩进逃课列表。因为是按顺序问的,出来的结果天然升序,老板的要求一步到位。

def findMissingElements(nums: List[int]) -> List[int]:
    attended = set(nums)               # 签到数据一键导入哈希表
    return [i for i in range(min(nums), max(nums) + 1) if i not in attended]

一趟流水线走完,没来的人自动列成一张干净整齐的缺勤清单,按学号从小到大排好,比老板的论文参考文献还规整。

我把缺勤名单截图往班群一甩:[2,3,5,6,7,8,10,11,12,13,14,16,17,19,20,21,22,23,26,27,28,29,30,31,32,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49]

群里安静了三秒。37号的头像弹出一个“?”:“不是学长,你这什么鬼名单,上次我签背面你没看见,这次我就上了个厕所——”

我秒回:“厕所上了五十分钟?你的五杀截图还在我朋友圈挂着呢。下周组会你替我讲文献,pdf已私聊。”


彩蛋· 逃课克星速查卡

  • List 遍历法:挨个遍历签到表,时间复杂度 O(n×m),小班点名还能凑合,学号一多,比校园网抢课还卡。
  • Set 哈希法:签到数据一键导入哈希集合,O(1) 光速查人。时间 O(n+m),多占的那点内存还没你手机里一款抽卡游戏大。

下次导师再让你“找缺失的元素”——不对,是找逃课的学生——别犹豫,直接 set 安排上。用合适的数据结构修理不合适的出勤率,然后你就可以安心打开原神清个体力。毕竟,37 号在讲台上替你讲文献的样子,比深渊使徒可爱多了。

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。