1. 一次“复习日”的完整复盘:第48天到底在做什么
打卡到第48天,很多人看到“复习”两个字,都会觉得这是偷懒的借口。但如果你也刷过算法题、准备过笔试或者追过竞赛,就会明白:复习才是把刷题量转化成实力的关键动作。今天的记录是从10:24到12:00,不到一个半小时,我却把最近一周最混乱的知识点全部重新捋了一遍。标题里的“0x3f”不是随手打的,混过算法圈的朋友都知道,0x3f3f3f3f常被当成“无穷大”的初始值,用来表示不可达状态、极大代价或者默认上限。拿它当打卡前缀,是想提醒自己:别看到难度很大的题就觉得像无穷大一样不可逾越,拆开看都是有限步骤。
为什么选10:24这个时间开始?其实不是刻意安排,前一天的复盘写到了夜里,早上起来处理完杂事,正好落到这个点。不过后来我发现这个时间段确实不错:早上的第一波困劲儿已经过去,距离午饭还有一段时间,大脑的清醒程度和空腹感都处于相对平衡。如果安排太早,容易因为睡眠不足而效率低下;安排太晚,又会和吃饭、午休撞在一起。所以10点到12点,作为一段“中型复习窗口”是非常合适的。整段时间控制在90分钟左右,也符合竞赛或笔试单场的长度,用来训练注意力的持久性刚刚好。
这篇内容不打算写成流水账,我把三个问题讲清楚:复习到底复习什么、90分钟怎么分配、哪些坑是连续打卡者一定会踩的。适合正在刷LeetCode风格的题库、准备秋招笔试、或者被算法竞赛折磨的读者;如果你才刚开始自学,也可以把里面的思路存下来,等学到一个月左右再拿出来用。
2. 复习内容拆解:核心算法模块怎么安排
2.1 第一优先级:重刷“又错又重要”的经典题
复习最忌讳从头到尾把题单扫一遍。那样做只是眼睛过了一遍,大脑根本没参与。我的做法是先把最近一周做错的题目拉出来,按两个维度打分:一个是“这题我错了几次”,另一个是“考点在面试或比赛里出现频次高不高”。两个维度都高的,就是今天必须碰的题。
举一个例子,有一道关于区间合并的题,我第一次做的时候思路是对的,但写代码时把合并条件写成了区间端点直接相等,漏掉了区间被包含的情况。这种错误很典型,不是不会,而是“边界条件看不全”。今天复习时,我特意把这道题找回来看,没有直接看代码,而是先盯着样例推导一遍流程,发现一旦出现第一个区间包含第二个区间的用例,我的代码就会把右端点错误地更新。找到这个根因比重新写十遍都管用。
所以我把刷题状态分成四类:
- 一遍过,且能给出两种解法:可以暂时不碰,只留笔记。
- 一遍过,但解法是猜的、没吃透:必须趁热重做。
- 重做后还在15分钟内卡壳:今日优先突破。
- 完全没思路、直接看了题解:周末集中消化,今天不硬碰。
这样筛选出来的题目数量通常不会太多,但每一题都是当前阶段的“要害”。复习不是为了让题目数量变多,而是为了让每一道做过的题都变成长期记忆。如果只是把同一道题机械地重复一遍,那和第一次刷完不看没有任何区别。真正有效的重做,是脱离提示、脱离题解,从头推导一遍完整思路。
2.2 第二优先级:错题本与卡壳点整理
我单独维护了一个文档,名字就叫“卡壳点”,不叫“错题本”。错题本往往只是把题目和解法贴在一起,翻多了容易产生虚假熟悉感;但“卡壳点”记录的是思考中断的位置,那个位置才是复习的最佳抓手。
举个例子,有一道用到线段树的题,第一遍做的时候我在 pushdown 阶段停了十分钟,一直纠结“一个节点同时有加法标记和覆盖标记时,到底谁先下传,下一层会不会被旧标记污染”。这种困惑如果只记录“线段树做区间赋值+加法”,下次复习还是想不起来。所以我在文档里写的是:“lazy 标记种类多时,先想清楚两种操作是否有顺序要求;赋值操作会覆盖加法操作,所以下传时要先处理赋值再处理加法,同时清零旧加法标记。”今天复习时,我看到的不是题目编号,而是这句话,瞬间就把整条逻辑链激活了。
我的卡壳点记录格式非常简单,固定三行:
- 我错在哪里:写出当时的错误想法,越具体越好。
- 正确的思路:用一句话说清楚。
- 触发的条件:例如“凡涉及区间修改,先检查是否要 pushdown;凡涉及合并区间,先考虑包含关系”。
每道题控制在三行以内。如果写多了,说明你还没抓住核心。复习的时候只扫三行,如果能秒答出对应的题目场景,就算过关;如果回答不出来,再翻原题的代码。这个方法帮我减少了很多“盲目刷题”的时间,也让复习从被动浏览变成了主动检索。
2.3 第三优先级:手写模板并默写关键代码
算法复习到最后,拼的不只是思路,还有手速和准确度。真实的笔试环境不允许你一边翻笔记一边写代码,所以必须把常用模板练成肌肉记忆。今天10:24开始的第一个复习动作,其实是默写模板。
我给自己列了一份短模板清单,大概十几段:快速幂、并查集、带权并查集、最短路(堆优化的 Dijkstra)、最小生成树 Kruskal、拓扑排序、线段树区间修改+懒标记、树状数组、字符串哈希、背包问题滚动数组写法。数量并不多,但每一段都是高频考场钉子户。
默写模板不是闭眼把代码背出来,而是边写边想每一行为什么存在。比如并查集的parent[x] = find(parent[x]),我写的时候会默念“这是路径压缩,目标是让当前节点直接指向根节点,降低下次查找深度”;union时判断按秩合并,是为了避免树退化成长链。如果写到一半停住,不需要马上翻答案,可以停下来想一想,再接着写。如果实在想不起来,就在那一行做个标记,等全部默写结束后再对照笔记。今天默写的是并查集、带权并查集和线段树基础操作。后面两道题用上了,我在中间环节重写 Dijkstra 时也顺手验了一遍堆优化的写法。
经验是:模板一定要改成自己的书写习惯,变量名可以随意,但结构必须是你在紧张时最熟悉的顺序。网上那些标准模板虽然工整,但如果平时没写过,考场上临时调用会非常别扭。用自己的排版方式重写一遍,就是一次最有效的记忆固化。
3. 90分钟的实操流程:10:24-12:00怎么分配
3.1 前20分钟:快速过一遍易错点
很多人拿到复习时间就直接打开题库,这很不明智。大脑从日常杂事切换到深度复习需要一个预热过程,如果一上来就死磕难题,大概率会在前十分钟内卡壳,然后烦躁,然后放弃。所以我把前20分钟固定用来“唤醒”。
操作方式很简单:打开卡壳点文档,只看三行记录,不看原题。一条一条往下扫,每看一条,在脑里重新推演一遍正确思路。能在20秒内理出来,就打一个对勾;如果犹豫了,就翻到这道题的代码结构处扫一眼,再合上屏幕复述。20分钟大概能过12条左右,如果超过12条也没关系,主次分明即可。
我甚至不看题目编号,只看知识点关键词。比如看到“差分约束 -> 判断负环 -> 用 SPFA 入队次数 n+1”这样的浓缩记录,整个人就像被提纲挈领地提了一下。这种方法特别适合长线复习,它不会让你陷入一道题的局部细节,而是快速重建整个知识网络。过了这个阶段,再进入写题环节,你会觉得脑子已经从“待机”变成了“在线”。
3.2 中间40分钟:限时重做3道中等题
复习阶段我特别反对慢慢悠悠地磨题。因为真实考试里没有“慢慢来”这个选项,刷题时如果从不计时,就会低估自己在压力下的思考速度。所以中间40分钟,我会切成两段:15分钟做一道重错题,10分钟做一个易混题,剩下15分钟做一道模板应用题。
比如今天选择的三道题分别是:一道区间合并(重错题)、一道带权并查集(易混题)、一道线段树区间赋值加求和的模板题。难度都不算高,但每个都命中了我当前薄弱点。重错题要求在没有任何提示的情况下,从头写到能通过样例。如果卡住超过5分钟,我不允许自己继续耗,而是把“卡在哪一步”快速写在草稿纸上,然后马上跳到下一道题。这看起来有点残酷,但实际效果比死磕一个小时要好。因为带着未完成的问题进入下一个任务,大脑后台会在潜意识里继续处理;而且第二道题往往里包含第一道题的某个相似点,转一圈回来时说不定就通了。
限时内我会刻意不用调试器,只输出中间变量。很多新人遇到错样例就喜欢断点单步,但模拟提交环境时没法这么做。靠中间结果反推问题,是一种更接近考场的调试能力。
3.3 后30分钟:复盘+写题解笔记
最后30分钟,是复习真正生效的环节。很多人做对三道题就把页面一关,觉得自己完成了复习。其实错了,如果不在结束后把“刚刚怎么想出来的”回放一遍,那些思路就还是悬浮在短期记忆里,睡一觉就没了。
我会按三个顺序来完成:
第一,对照刚才写下的卡壳位置,看它们和曾经的记录是否重合。如果重合,说明上次没有根治,要补一条更强的触发条件;如果没重合,就是暴露了新问题,值得高兴。
第二,给三道题各写三句话的“思路摘要”。例如“带权并查集的本质是把每个节点和根之间的权值关系维护起来;find 过程中要先把父节点的权值递归累加,再更新当前节点的权值;union 时注意两个根之间的权值等式要反号。”用这种话口述出来,而不是贴代码。如果讲不清楚,就说明你还欠一点理解。
第三,更新模板库。如果做题过程中发现某个模板需要补充边界条件,我会在模板对应行加注释,而不是重抄。比如“区间修改完全覆盖当前节点时,先更新 sum 和 lazy,不递归;否则必须先 pushdown 再向下走,回溯时 pushup”。这些自己踩出来的细节,比任何教程里的注释都值钱。
复盘笔记不追求长,每道题50字到100字就足够。如果一道题的笔记超过150字,说明思路还不够干净,需要再压缩。
4. 复习日常见问题与排查技巧
4.1 一复习就犯困,怎么办
我在打卡第48天的过程中,最常遇到的不是“不会做”,而是“一看旧题就困”。原因很简单,复习时缺少新鲜刺激,大脑会默认进入节能模式。每次打开错题本,眼皮就开始打架。
破解方法有两个。第一,把复习改造成“限时挑战”。只要开始倒计时,并且盯着一道题从开始到结束花了多少分钟,注意力就会自动收拢。倒计时带来的紧迫感可以对抗“旧题没有挑战性”的错觉。第二,每复习15分钟,起身走半分钟,倒杯水或者看看窗外。不要小看这种微中断,它能让大脑重新加载注意力资源。如果你觉得自己完全看不进去,还可以换一种姿势,比如从椅子上挪到窗边站着看笔记。空间位置的改变往往能打断困意循环。
还有一个坑,就是千万不要把复习安排在大餐之后。我有一段时间习惯中午一点多开始复习,结果桌上摊着笔记,脑子里全是碳水带来的困意。后来把复习挪到10点到12点,情况立刻好转。
4.2 重刷还是会卡,到底记住没有
如果你上周做对的题,今天又卡住了,完全不代表你变笨,更不代表你白学了。上一周的记忆没有被提取到长期区域,这是每个人都会遇到的现象。重要的是找到“为什么卡”。
最常见的卡壳原因是“你能认出这道题,但想不起第一步该干什么”。这是提取线索太弱的表现。解决办法是给知识点建立“路由条件”。比如看到区间问题,先问自己“是否满足可合并性?如果满足,可以考虑线段树或树状数组;如果不满足,可能是分治或差分”。看到动态规划,先问“最后一步的状态是什么?子问题怎么定义?状态转移之间有没有循环依赖?”这些提前储备的条件反射,能让你在遇到类似题时更快定位方向。
另一种情况是,你觉得卡住了,但只要你翻一下当时的笔记就能继续做。这说明你的核心问题不是能力,而是缺少“主动提取”的练习。所以复习时一定要先不看解析,逼自己干想。哪怕只想出两步,再翻笔记,翻完合上,继续写。这个“先回想、再验证”的组合,比单纯看解析要牢靠得多。
4.3 时间不够用,要不要硬啃
复习的时候经常会遇到:“再给我十分钟我就能调出来”的情况。但如果你是从10:24开始的,到了11:50还卡在一道题上,我建议直接收手,不要硬啃。复习的目标是查漏,不是证明自己今天一定要解出这道题。漏点不会因为硬啃就消失,反而会因为焦虑而变得更顽固。
我给自己定的原则是:单道题连续卡壳超过15分钟,立刻停止,把这个位置存档。所谓存档,就是记录“我目前想到了什么、卡在哪个条件转化上、以及下一步准备试什么方向”。第二天再来看时,资料还是热的,但大脑经过了休息,往往一眼就能看出新路子。
如果距离结束只剩10分钟,那你更不应该开始新题。不如直接翻开卡壳点文档,把最容易忘的五条过一遍。这种收尾式复习的价值,常常比硬做一道题更大。
4.4 复习与刷新的节奏怎么平衡
复习和刷题的关系,不是零和博弈。刷题负责扩展题型视野,复习负责把新题型变成旧题型。好比读书和背书,只读不背,最后一本本翻完,脑子里全是模糊影子。
我的习惯是保持一比三到一比五的节奏。也就是每复习一天,后面至少跟着三天正常刷题。比如说今天复习完,明天和后天就投入新题,周五再做一个短复习。如果连续多天只复习不刷新,心理上容易产生停滞感;如果连续刷新从不复习,看起来进度很快,但到第30天回头一看,前面十天的内容早就忘了。两种极端都不好。
实际操作时,我还注意把复习内容与最近三天的新题挂钩。今天的复习重点明显偏向近一周碰过的知识点,而不是翻到一个月前的老黄历。距离越近的错题,复习性价比越高。老题可以留到周末或月底做一次大扫除式回顾。
5. 给长期打卡者的几条实战建议
5.1 不要迷信“连续打卡天数”
很多人连续打卡几十天,就误以为自己实力已经涨了那么多。说实话,连续打卡只能证明你保持了学习动作,至于动作有没有落到实处,完全是另一回事。与其盯着连续性数字,不如定期看“掌握度指标”。
我每周统计两个数字:一个是复习完成率,计划复习的题有百分之多少完成了“当日重做”;另一个是重做通过率,即重做时能在规定时间内通过样例的比例。如果通过率在上升,说明复习策略有效;如果连续两周原地踏步,就该考虑是不是复习方式太温和了——比如总看笔记而不动手,或者总重复那些已经会了的简单题。
打卡这件事本身没错,错的是把打卡当成终点。真正的里程碑,是某一天你发现以前要花一小时才能看懂的题解,现在十分钟就能复述出来。那种“突然变轻松”的信号,才是已经形成能力迁移的证据。
5.2 复习日要敢做减法
今天10:24到12:00的时段,如果换成别人,可能会安排10道题再加两个新知识点。但我只做了3道重做题和3段模板默写,之后还有时间从容地复盘。表面看效率不高,实际上每一步都有充分的思考余量。
复习的时候,大脑很容易进入到“完成任务模式”:看见一道题,哪怕没有理清思路,也急着把代码写完,然后打勾进入下一道。这种状态下的复习,写出来的代码只是对答案的拙劣模仿,对长期记忆没有任何帮助。要破除这个状态,最有效的方法就是故意少安排一些内容,让每个环节都留出“为什么”的思考间隙。
我会在复习日只计划80%的内容,剩下20%的空白用来应对卡壳、走神和意外延展。如果提前完成了,就随意翻翻自己之前写过的题解运气,说不定会有新启发。做减法的本质,是给深度思考让位。
5.3 单日时间短,就用“碎片化整理”
不是每天都有一整块时间可以复习。你可能只有通勤路上的20分钟,或者午休的15分钟。这种碎片时间不适合重写代码,但非常适合做“卡壳点扫描”。
通勤的路上,我会用手机打开自己的笔记,只读三行记录,然后在脑子里快速回忆对应的解题框架。不需要打开代码,甚至不需要打开原题,只做“看浓缩笔记 -> 回忆细节”这一个循环。这样做二十条下来,也就十几二十分钟,却能有效维持知识的热度。别小看碎片时间,我有很多次在坐车时想到一个之前没想明白的细节,晚上回去一验证,果然通透了。
碎片化整理的另一层意思,是随手记。如果你在做某道新题时突然想到“这和我之前错的某个边界条件好像”,不要犹豫,马上在手机备忘录里记一句。这些东西往往是跨章节联系的线索,是深度复习最好的导火索。
5.4 用“输出”检验复习效果
学习的真相是:你以为自己懂了,讲出来才发现全是漏洞。所以我非常推荐“以讲代测”的复习方式。每到周末,从本周做过的题里随机抽三道,不看题解,假装面前坐着一个朋友,把三道题的思路用几分钟讲清楚。可以真的说给学习搭子听,也可以录一段语音自己回放。
如果讲的过程非常流畅,说明知识已经内化;如果讲到一半突然沉默,比如不知道“为什么这里要用倒序遍历容量”,停顿的那一刻,就是下一次复习的切入点。我在一次复盘中就经历过类似场面,当时讲到背包问题时卡住了“滚动数组为什么必须倒序”的解释,后来重新翻书才彻底想明白,原来是为了防止本轮更新被当前物品的旧状态覆盖。那次卡壳比多做十道题都值钱。
输出方式可以多样,写短题解、讲给别人、或者画一张简单示意图,都算输出。关键是不要只在脑子里默念,因为大脑会自己骗自己。手动输出能暴露更多细节。
今天这90分钟下来,我的最大感受是:复习不是简单地把旧东西再看一遍,而是带着问题去验证自己的思维方式。10:24到12:00,没有新增任何炫酷新题,也没有打开新章节,但就是把过去一周的短板又补了一圈。刷题这件事,新鲜感当然重要,可那些真正让你安心的知识点,基本都是靠反复复习才扎根的。
最后再分享一个小技巧:每次复习结束时,我会把今天的复习主题压缩成一个短语,写进日历。比如“并查集路径压缩”“线段树lazy传递”“带权并查集合并公式”。第二天开始学习前,先看一眼这个短语,再决定今天的新题方向。如果昨天复习是的图论,今天就刻意多安排一题图论相关的新题,以新带旧;如果昨天复习的是动态规划,今天就先默写一遍背包模板再进入新章。这样周与周之间就形成了一个连贯的螺旋结构,而不是每天醒来都像失忆一样重新找出路。我从第16天开始用这个习惯,一直坚持到现在的第48天,它也是让我在复习日里真正“有收获”的核心原因。