很多人问我LeetCode到底怎么刷才有效,我通常会给一个很反直觉的回答:别急着刷题,先定策略。我自己在刷题这件事上踩过最大的坑,就是跟风刷题,今天一道数组明天一道图论,三个月后回头一看,写过的题全忘了。后来我给自己定了一套方法,代号“策略A”,核心只有三个字:少而精。这套策略不追求刷题数量,也不迷信“千题大神”,而是用LeetCode热门100题做骨架、用高质量题解做复盘、用周赛做校准。如果你正处于刷了二三十题还是没手感、或者刷了三百题还是怕新题的阶段,这篇内容就是写给你的。
1. 策略A的起点:为什么我先啃“热门100题”而不是海量刷题
1.1 热门100题不是题单,是考点分布图
很多人对“热门100题”有个误解,觉得它就是个入门题单,刷完就算打卡成功。我一开始也这么想,后来才发现,这100题真正的价值不是“题目本身”,而是它背后那张高频考点分布图。
我做过一个粗略统计:LeetCode热门100题里,数组和哈希表大约占两成,二叉树和链表占两成,双指针和滑动窗口占一成多,二分查找、动态规划、回溯、图论各占一部分。这个分布其实非常接近真实面试和竞赛里出现频次最高的知识点。换句话说,你不用去网上搜“面试必刷清单”,把这100题的标签统计一遍,你就知道该在哪些方向上花时间了。
所以策略A的第一条原则是:把热门100题当成地图,而不是任务清单。我拿到一份题目列表后,做的第一件事不是从第1题开始刷,而是把所有题目按标签分组,统计出分布,然后按照“高频考点优先”的顺序去逐个击破。这比按题号顺序刷效率高很多,因为你不会在某个冷门知识点上卡两周,也不会把大量时间花在已经熟练的题型上。
1.2 我的第一轮执行节奏:按标签分组,不按题号
策略A执行的第一步,不是定计划表,而是先做一个简单的“标签分组”。我把热门100题里每道题的标签抄下来,归类整理,然后给自己定了一个六周的第一轮节奏。
| 周次 | 主攻方向 | 代表题型 |
|---|---|---|
| 第1周 | 数组与哈希表 | 两数之和、字母异位词分组 |
| 第2周 | 双指针与滑动窗口 | 无重复字符的最长子串、盛最多水的容器 |
| 第3周 | 二叉树与链表 | 二叉树中序遍历、反转链表 |
| 第4周 | 二分查找与栈 | 爱吃香蕉的狒狒、每日温度 |
| 第5周 | 动态规划 | 爬楼梯、打家劫舍 |
| 第6周 | 回溯与图 | 全排列、岛屿数量 |
这个节奏的关键在于“按标签集中刷”,而不是今天做一题哈希、明天做一题DP。我自己试过的体会是:人的短期记忆对“同类问题的模式”特别敏感。如果你连续三天只做滑动窗口,你会发现第四天再遇到类似题目时,脑子里的反应速度明显变快,而且对双指针的移动条件会产生肌肉记忆。这种“手感”是靠分散刷题很难获得的。
每天的量,我控制在3题左右。很多人一上来就给自己定“每天10题”,坚持不了一周就会崩。3题的意义在于:你还能留出时间看题解、写笔记、重做错题。策略A的核心不是“做更多题”,而是“每道题都留下点东西”。
1.3 热门100题里最容易让人误判的几类题
刷完第一轮热门100题后,我最大的感受是:不能用题面长短判断难度。
有几类题特别容易误导人。一类是“题面很长,核心很简单”,比如很多带背景故事的题,讲了一大段场景,最后发现就是排序或者哈希去重。另一类是“题面很短,坑很深”,比如那道“爱吃香蕉的狒狒”,你第一眼以为就是个模拟循环,实际上考的是二分查找的边界判断。
还有一种更隐蔽的误判:看起来是“数据结构题”,其实是“算法题”。比如有些二叉树题,你用递归能写,但考的是迭代和栈模拟;有些数组题,暴力能做,但考的是双指针的单调性分析。我在第一轮里经常犯的错误是“会做就算完”,没有去深挖这道题真正想考的模式是什么。后来我把每道题的问法总结成一个句子,比如“这道题本质是在有序区间上找满足条件的最小值”,再遇到类似题时就能快速归类。
2. 题解的正确打开方式:从“爱吃香蕉的狒狒”看透二分查找
2.1 这道题为什么值得反复看
LeetCode上“吃香蕉”那道题,我至少重写了五遍。每次重写都有新的收获,因为它几乎把二分查找里所有容易踩的坑都集合在了一起。
题目本身很简洁:有一堆香蕉堆,每堆有若干根,狒狒每小时吃一堆,并且每小时最多吃k根。如果一堆少于k根,那这一小时就只吃这一堆,不能再去别的堆吃。现在要求在h小时内吃完所有香蕉,求最小的每小时吃香蕉速度k。
很多人第一次看到这道题,第一反应是模拟:从k=1开始试,直到某个k能让总时间不大于h。这样当然能做,但如果piles数组很大,k的范围也很大,暴力枚举就会超时。而它真正的考点是:吃香蕉的时间T(k)是关于k的单调递减函数,k越大吃得越快,T越小。我们要找的是“让T(k) <= h成立的最小k”,这正好是二分查找的经典场景。
2.2 我第一次看题解漏掉的关键:搜索空间的边界
这道题我第一次看题解时,以为自己懂了,合上答案开始写,结果卡在边界条件上。最关键的漏掉点有三个。
第一个是搜索空间的右边界。我当时想的是,k最大可以是所有香蕉总数,因为一小时最多吃k根,理论上可以一次吃完所有堆。但实际不需要,把右边界设为max(piles)就够了。因为当k大于等于最大的那一堆时,每一堆都只需要一小时,总时间等于堆数,再增大k也不会让时间更短。把右边界设为总和,虽然逻辑上没错,但会让二分的范围大很多,而且无形中增加了思考负担。
第二个是向上取整。计算某一堆吃掉需要几小时时,如果piles[i]小于k,耗时是1小时,而不是piles[i] / k的小数。正确公式是(piles[i] + k - 1) // k,也就是向上取整。我第一遍写的时候直接用了piles[i] // k,遇到piles[i]小于k的情况就算错了。
第三个是更新的方向。我们要找的是“最小可行k”,所以当某个k可行时,说明k还有可能更小,应该把右边界往左收;当某个k不可行时,说明k太小了,必须把左边界往右收。这个方向如果搞反,二分就会陷入死循环。
我后来给自己总结了一句口诀:求最小可行值,可行就收右边界,不可行就收左边界。再配合标准模板写起来就很顺:
def minEatingSpeed(piles, h): def can_finish(k): total = 0 for p in piles: total += (p + k - 1) // k return total <= h left, right = 1, max(piles) while left < right: mid = (left + right) // 2 if can_finish(mid): right = mid else: left = mid + 1 return left2.3 把题解变成自己的三类笔记模板
以前我看题解,看完觉得“原来如此”,一周后就忘了。后来我改成了一种更笨但更有效的方法:把题解拆成三类笔记。
第一类是“问题识别笔记”。用一句话说明这道题的本质特征。比如“吃香蕉”这道题,我的笔记写的是:当答案随参数单调变化,并且要求某个条件下的最值时,优先想二分。这句话比把整道题抄一遍有用得多。
第二类是“边界陷阱笔记”。只记录那些让我卡壳的边界条件。比如“向上取整的写法”“右边界为什么是max(piles)”。这些内容不会出现在题解的第一屏,但恰恰是面试和比赛中最容易扣分的地方。
第三类是“重写验证笔记”。看完题解后,合上答案,自己从头写一遍,然后故意改一两个条件,比如把h换成等于堆数的极端情况,验证代码是否正确。我会把这类验证过程也记下来,记录“我改了什么条件,结果为什么变了”。这一步能帮我把题解消化成自己的思维模式,而不是背代码。
3. 周赛430实战:用比赛校准策略的偏差
3.1 我在周赛430里栽的跟头:题型识别比手速更重要
打周赛是我检验策略A最狠的方式。第430场周赛里,我犯了一个特别典型的错误:有一道题我一眼看上去觉得是模拟,按着题目描述里的顺序老老实实写循环,结果有个数据范围很大的测试用例直接超时。后来看题解才发现,这道题的核心是二分查找,因为答案随参数单调变化。
那次之后我复盘了很久。问题不是出在手速上,而是出在“题型识别”上。我看到题目里有循环、有重复操作,就条件反射地写模拟,但没去分析操作的单调性。这正是策略A反复强调的:“先识别模式,再动手写码。”在周赛那种紧张环境下,人最容易退回惯性思维,而惯性思维恰恰是新题里最大的坑。
我把这个教训记进了周赛复盘表,并且在之后几周的刷题里刻意训练:遇到任何题目,先等十秒钟,问自己三个问题——这个结果是否随某个值单调变化?能不能用二分?能不能用双指针?这三个问题帮我避免了很多次“一上来就暴力”的冲动。
3.2 赛后复盘的两张表:失误分类表+知识点遗漏表
很多人打完周赛就去看别人的代码,看完觉得自己会了,其实收获非常有限。我给自己定了一个强制流程:赛后两小时内,必须填两张表。
第一张是失误分类表,记录这次比赛里出现的失误类型。我的分类大概有四种:审题失误、算法选错、边界条件、实现细节。每次比赛后,我会把每道题的错误原因归到某一类,然后统计哪类最多。比如第430场周赛,我的失误大部分是“算法选错”,这说明我在做题前没有充分分析单调性,而不只是“手抖”。
第二张是知识点遗漏表。我会把每道题涉及的核心知识点列出来,再对比自己在比赛时有没有想到。没想到的,就代表这个知识点还没形成条件反射,需要回到热门100题或专题刷题里去补。这样周赛就不再是单纯的“刷排名”,而是一个精准的查漏工具。
我整理了一个简单的模板,可以供参考:
| 题号 | 我的做法 | 正确做法 | 失误类型 | 遗漏知识点 |
|---|---|---|---|---|
| 周赛430 T2 | 暴力模拟 | 二分查找 | 算法选错 | 单调性分析 |
| 周赛430 T3 | 递归超时 | 记忆化搜索 | 实现细节 | DP状态定义 |
只要你连续坚持打几周周赛,这张表就会告诉你:哪些坑是偶尔踩,哪些坑是反复踩。反复踩的,就是策略A下一个阶段的主攻方向。
3.3 周赛成绩波动说明什么,不说明什么
如果你的周赛成绩时好时坏,不一定是你状态不稳,也可能是因为不同知识点的掌握程度差距太大。比如我打第428场周赛时,前三题全是链表和栈,我做得很快;到了第430场,出现了一道很隐蔽的二分题,我就卡住了。成绩波动最直接的信号,是你对不同题型的熟练度不均衡,而不是你的“智商”或者“手感”变了。
这一点特别重要。我见过有人连续两次周赛失利后,就开始怀疑自己适不适合编程,其实完全没必要。周赛更像是一张体检报告,单次指标波动不代表什么,但连续几次都暴露同一个问题,就需要认真对待。
还有一点,周赛成绩不说明“你已经掌握了某类题”。即使某一场比赛你AC了前三题,也不代表这些知识点真的进入了长期记忆。只有当你隔两周后还能不看题解独立写出同类型题目时,才算真正掌握。这也是我为什么一直强调“重写”和“复盘”,而不是只看AC率。
4. 策略A的执行细则与避坑清单
4.1 三明治式刷题法:热身、专注、整理
在执行策略A的过程中,我逐渐把自己的刷题节奏固定成“三明治式”,效率比以前高了不少。
第一层是热身,控制在十分钟以内。通常我会翻开昨天做过的题,不看代码,只口述一遍思路。如果说得清楚,说明这个知识点还在;如果卡住了,说明还没真正消化,需要再重写一遍。这个热身动作看起来简单,但它能帮你把“短期记忆”转化为“长期记忆”。
第二层是核心,也是最重要的部分。我会选一道当天主攻方向里的新题,给自己设定一个30分钟的时间盒。前5分钟读题并写下已知条件,再花10到15分钟尝试解题,剩下的时间用来验证边界和失败原因。如果30分钟内没做出来,就进入下一步“整理”,而不是继续死磕。
第三层是整理。用我在前面说的三张笔记模板,把这道题的收获写下来,包括问题识别、边界陷阱、重写验证。整理完成后,我会把题目标记为“需要三刷”,放进一个单独的列表。这个列表里的题不会立即清除,而是要隔三天、隔一周再各刷一次。这样做的好处是,你始终知道自己还有哪些“欠账”没有还清。
4.2 遇到不会的题,正确顺序是什么
我见过很多人在一道题上卡两个小时,美其名曰“独立思考”。我不反对独立思考,但在刷题阶段,这种死磕的效率太低了。我的原则是:不要在一道题上连续卡超过30分钟。
具体顺序可以这样:前5分钟,自己判断题目属于哪种模式,写出最暴力的解法;再给15分钟优化,如果优化不动,就允许自己看提示或者题解。但看题解不是终点,看完后必须合上答案,从头写一遍代码。这一遍才算真正开始学这道题。
如果看了题解还是写不出来,问题大概率出在前置知识上。比如你对“滑动窗口的右边界如何扩展”理解得不扎实,那道题给你什么题解都属于空中楼阁。这时候我会回到热门100题里,把同类型、更基础的题目重刷一遍,而不是继续硬啃难题。大多数人卡题,不是因为难题太多,而是因为基础题的知识点没有形成体系。
4.3 我用策略A三个月后的变化:从周赛1题到稳定3题
这套方法我坚持了三个月,变化最明显的是周赛表现。最开始我打周赛基本只能做出第一题,第二题经常写一半就超时。三个月后,我基本能稳定做出前三题,偶尔还能摸到第四题的思路。这个进步不是线性的,中间有一段时间连续几次周赛成绩都很烂,但复盘表告诉我,这段时间的失误类型正在变化。
从最初的“看到题没有思路”,变成了“有思路但边界处理不好”,再到后来的“思路对但实现效率不够”。每一次变化背后,对应的都是某一类题型的熟练度在提升。所以如果你也在刷题,建议不要把注意力只放在“能不能AC”上,可以试着记录自己做错的方式。只要错误的类型在变化,就说明你正在进步。
在我的记录里,前一个月AC率不到四成,后两个月稳定在六成左右。这个数据算不上亮眼,但对我来说,最关键的变化是:碰到没做过的新题时,我不再慌了。我会先问自己“这个结果是不是单调的”,然后尝试把它归到二分、双指针、动态规划或者回溯这些已知模式里。这种确定感,比任何AC率都重要。
4.4 策略A不适合谁
策略A并不是万能的。我也得诚实地给它划一个边界。
如果你是那种“下周就要面试,这周必须突击”的选手,策略A的六周专题节奏就太慢了。这种情况下,你需要的是直接刷高频面试题,甚至可以直接看公司面经去定向准备,而不是先花时间建体系。策略A更像是给“能够持续投入三个月以上”的人准备的。
另外,如果你刷题的动机是“享受刷题数量突破1000题的快感”,策略A也会让你很难受,因为它会反复要求你做同一道题、重写你已经AC过的题。但我觉得,多数人刷LeetCode想要的并不是数字,而是真正面对新题时能解出来的底气。如果你也想要这份底气,策略A值得一试。
最后再分享一个小技巧:每周固定打一场周赛,不管考多差都要打,这可能是策略A里最便宜的一次体检。比赛不用复习,直接裸考,反而能暴露你最真实的短板。我在连续打了十场周赛之后才发现,自己最怕的不是难题,而是“看起来像模拟题的二分题”。后来每次看到吃香蕉、找根号这类题面,我都会先问一句:这个值是不是单调的?如果是,大概率就是二分。这个小习惯就是从“爱吃香蕉的狒狒”那道题和那几场周赛里长出来的。希望这套策略A,也能帮你少走一点弯路。