我到现在还记得第一次在力扣上提交失败的画面:红色的“解答错误”,测试用例卡在第47个,我盯着屏幕看了五分钟才看懂它到底在测什么。那之后我在力扣上刷了三年,前前后后写了一千多道题(其中很多是反复二刷三刷的),也从“看到二叉树就头晕”的状态,走到现在能比较从容地把一道难题拆成若干子问题。身边经常有人问我,力扣刷题到底该按什么顺序,有人一年刷了500题还是心里没底,也有人只刷了100题就拿到满意的结果。差距不在数量,在于有没有把刷题当成一条需要规划、复盘、纠偏的长期路线,而不是一款无脑刷进度的游戏。
这篇文章想写的,就是这条“力扣刷题之路”上我实际走出来的东西:怎么确定起点、怎么分阶段选题、每个模块的击破套路、错题怎么管理、上班之后时间怎么挤、以及如何熬过刷到中段必然出现的倦怠期。它更适合那些准备认真刷题的人,无论你是刚起步的新手,还是已经刷了百来题正在迷茫的老手,都应该能找到对应阶段的用法。
1. 这条路到底通向哪里:先想清楚你在为什么刷
很多人打开力扣的第一件事就是按题库顺序从第1题开始做,但很少有人停下来想一个问题:我到底为什么刷题?想清楚动机,比多刷五十道题重要得多,因为动机不同,选择的题库范围、做题深度、时间投入完全不是一回事。
1.1 四种刷题动机,四种完全不同的路线
我把这些年接触到的刷题人群大致分成四类,你可以对照一下自己在哪个位置:
| 动机类型 | 典型画像 | 题库选择 | 刷题深度 |
|---|---|---|---|
| 面试突击型 | 近期要面技术岗,目标明确 | 高频题、热题榜单、公司题库(如果有) | 重解题速度与边界覆盖,求稳 |
| 能力成长型 | 非科班转行,或科班但基础薄弱 | 按经典知识模块系统性刷 | 重理解,每道题吃透 |
| 算法爱好者 | 比赛党、追求思维乐趣 | 周赛、困难题、细分专题 | 重一题多解与复杂度极值 |
| 随大流型 | 看别人刷我也刷 | 没方向,今天简单明天困难 | 最浅,容易放弃 |
这四类里,前两类占据了大多数人。如果你是面试突击型,那么“以终为始”就是你的第一原则——先搞清楚目标岗位对算法考察的深度,再决定刷哪些题。如果你是能力成长型,我建议把眼光放长,不要指望刷完三百道题就脱胎换骨,真正的变化发生在你把每个模块的规律嚼碎之后。
我自己属于第二类和第三类之间。前半年纯属为了补数据结构短板,后来慢慢刷出兴趣,才开始追周赛和一题多解。回头看我见过的不少案例,A同学用了三个月每天刷四题,结果面到动态规划还是懵,原因就是他只会背某一道题的解法,换一种包装就不会了。B同学刷得慢,但每道题都写复盘,三个月后能力明显上了一个台阶。所以先别急着问“每天刷几题”,先问自己是哪一类人。
1.2 “AC就是完成”的想法,恰恰是效率最低的
很多人把一道题提交通过当成这件事的终点,我恰恰认为那是起点。只追求AC,刷到的只是“这一道题的答案”,而不是“这一类题的解法”。真正的完成标准应该是:你能不能在提交通过之后,回答出下面几个问题。
第一,这道题的时间复杂度和空间复杂度是多少?最优解能不能再降一个量级?第二,代码的边界情况处理全了吗?空输入、极端长度、溢出,这些是不是都考虑过?第三,这道题和之前做过的哪些题是同一类?它们的共同套路是什么?
能做到这三点的题,才算真正吃透。我在刷题笔记里给每道题都打了一个“完成度”标签,一刷通过只能算50%,写完复杂度分析和同类题总结才算100%。如果你现在做题从来不关心复杂度,那么第一件事不是去多刷题,而是把之前刷过的简单题翻出来,把复杂度逐题标注一遍。这个过程很枯燥,但它是你从“代码搬运工”走向“会设计算法”的必经之路。
2. 从零到三百题的分阶段规划:题库不是跑步机
我见过太多人把力扣题库当成跑步机,每天上去跑一小时,从第1题挨着做,做到150题左右就做不动了,因为后面的题目难度陡增。问题不在于你不够努力,而在于你缺少阶段划分。力扣题目数量已经破千,盲目开刷和裸考没有区别,你需要一套根据自己当前能力动态调整的选题策略。
2.1 四个阶段:入门、基础、进阶、冲刺
我给自己的刷题路划分成四个阶段,每个阶段只做该阶段该做的事。
| 阶段 | 题量范围 | 核心侧重点 | 建议周题量 |
|---|---|---|---|
| 入门期 | 0–60题 | 数组、字符串、哈希表、链表基础操作 | 10–14题 |
| 基础期 | 60–200题 | 二叉树、DFS/BFS、双指针、回溯 | 8–10题 |
| 进阶期 | 200–400题 | 动态规划、贪心、图论、并查集 | 6–8题 |
| 冲刺期 | 400题以上 | 高频题二刷、困难题突破、限时模拟 | 持续保持手感 |
入门期先别碰“困难”标签,自闭刷题只会打击信心。我在入门期给自己定了一条规矩:只做通过率高于50%的简单题和少量中等题,目标就一个,熟练掌握一门语言的基础写法,把数组遍历、哈希表增删查、链表节点交换这些动作练到条件反射。这个阶段最忌讳的就是边查语法边想算法,两手抓两头都不硬。
基础期开始接触递归和树,题目难度会明显上一个台阶。这时候每道题花的时间可以放宽到一小时,但注意不要卡太久,卡题超过半小时没有思路就先看题解,看懂后合上书自己写一遍,效果远好于死磕两小时。到了进阶期,动态规划和图论会让很多人再次崩溃,这时候不要贪多,一天一到两道难题就够,重点是把套路提炼出来。四个阶段走完,你再回头看那些曾经让你崩溃的题目,会有一种很真实的通透感——题目还是那些题目,但你的眼睛已经变了。
2.2 每天几题、每题卡多久,其实有公式
总有新手问,我每天到底刷几题合适?说实话没有标准答案,但有一条经验可以作为参考:把“每周有效完成题数”定在8到14题之间,比每天硬性规定“必须刷3题”要科学得多。原因很简单,刷题不是计件工作,一周内你会遇到加班、聚会、状态低落,允许自己某天不刷,但周末补上,这样的节奏才可持续。
做题过程中时间卡点怎么定?我自己的规则是“15分钟原则”:拿到一道中等题,如果15分钟内没有任何有效思路,直接看题解。这不是偷懒,而是高效利用学习资源——力扣的大多数中等题都是某种已知套路的组合应用,靠自己想通并不比直接看题解更高效。但看完题解后必须做一件事:合上题解,自己从零写一遍,然后在笔记里记下“为什么我没有想到这个思路”,这才是看题解的价值。
从零开始的第一周,我建议你这样安排:前两天只刷数组和哈希表的简单题,每天三题;第三天开始接触链表的简单题;第四天尝试两道简单难度的二叉树入门题,感受递归的写法;第五天到第七天,把前四天做过的所有简单题重新读一遍,不写代码,只回忆思路和复杂度。这一周看似题量不多,但它能帮你建立对“刷题”这件事的正确体感。
3. 常考模块逐个击破的实操心法:不要按题目编号顺序刷
力扣题库不是线性的,按编号从1刷到500,你会先把数组、字符串、链表这些基础题做完,然后一头撞上动态规划的墙。更好的策略是按知识模块横向击破,把一个套路练熟再换下一个。下面我挑几个最劝退、也最高频的模块,说说我自己怎么打。
3.1 遍历就是一半数据结构题的底子
很多人搞不定二叉树和图,问题往往出在“不会写递归”。其实递归没有那么玄乎,你只需要记住一个骨架:处理当前节点、递归调用左右子树、考虑结束条件。以二叉树的前序/中序/后序遍历为例,核心代码就这几行:
def dfs(node): if not node: return # 先序位置:先处理当前节点的逻辑 dfs(node.left) # 中序位置:处理完左子树后的逻辑 dfs(node.right) # 后序位置:处理完左右子树后的逻辑关键在于理解递归函数中不同“位置”的语义。先序位置在调用左子树之前,适合做“当前节点需要先被处理”的操作;中序位置在左子树之后、右子树之前,天然对应排序二叉树的中序遍历结果;后序位置在左右子树都处理完之后,常用于“先拿到子问题的结果,再汇总给父节点”的计算。能把这三个位置吃透,树的题目就解决了一大半。
链表题也是一样,说到底就是两个动作:指针怎么走、节点的指向怎么改。我刷链表题时会在草稿纸上画每一步的节点指向图,把prev、cur、next三个指针的移动顺序画清楚再写代码。不要嫌画图慢,画得慢、写完快,这比盯着代码空想要效率得多。
3.2 动态规划劝退点在哪,五步法帮你稳住
动态规划是公认的“分水岭”,太多人卡在这一关。“这道题我明明看过题解,换一个题目就不会了”就是我听过最多的抱怨。其实动态规划题有一个通用的分析框架,我称之为“五步法”:定义状态数组的含义、推导状态转移方程、确定初始化条件、确定遍历顺序、最后打印dp表检查。
拿最简单的一道二维路径问题举例——机器人从左上角走到右下角,每次只能向右或向下,求不同路径数。按照五步法,第一步,定义dp[i][j]为走到第i行第j列的不同路径数;第二步,很容易想到dp[i][j] = dp[i-1][j] + dp[i][j-1],因为每个格子只能从上方或左侧到达;第三步,第一行和第一列的格子都只有一种走法,初始化为1;第四步,从上到下、从左到右遍历;第五步,写完后在脑子里按表格推一遍。
def unique_paths(m, n): dp = [[0] * n for _ in range(m)] for i in range(m): dp[i][0] = 1 for j in range(n): dp[0][j] = 1 for i in range(1, m): for j in range(1, n): dp[i][j] = dp[i-1][j] + dp[i][j-1] return dp[m-1][n-1]这套方法看起来很笨,但它是破局的关键。我把第二三四五步统称为“半机械动作”,很多DP题难就难在定义状态这件事上。状态定义不唯一,多试几个角度——是dp[i]表示前i项的结果,还是dp[i][j]表示区间i到j的结果,还是dp[i]表示以i结尾的结果?把常见状态定义模式收集到手,等面试场上碰到DP题,至少有几套牌可以打。
3.3 回溯与搜索:先画决策树,再写代码
回溯算法在“排列组合类”题目里高频出现,也是许多人觉得“剪枝”是最难的地方。我刚开始学回溯时,总想一步到位写出最优解,后来发现正确路径是:第一版只做纯粹的穷举,不管效率,先把所有可能列出来;跑通之后再考虑剪枝,剪掉那些已经可以判断不可能的分支。
回溯本身有一个万能的递归模板:
def backtrack(路径, 选择列表): if 满足结束条件: 记录当前路径 return for 选择 in 选择列表: 做选择 backtrack(路径, 选择列表) 撤销选择关键在于“做选择”和“撤销选择”的对称——递归进去是什么状态,回来就得是什么状态。我见过太多新手在这里出错,选了但是忘记撤销,结果第二次循环时状态已经乱了,排错排到怀疑人生。一个最笨也最有效的方法:在撤销选择那一行打印当前路径,把递归过程完整打出来看,状态走没走对一目了然。
4. 复盘才是刷题的主战场:错题管理的三条铁律
如果只让我给一条最重要的建议,那就是:刷题的数量由你刷过的题目总数减去你忘记的题目数量决定。这句话不好听,但这是事实。我观察了很久,绝大多数刷了300题仍然觉得空落落的人,缺的都是复盘这套动作。错题管理不是让你攒一堆收藏夹,而是有一套可执行、可坚持的机制。
4.1 每道题刷完,至少留下四条记录
我在本地用文档维护了一个刷题档案,每道题占一个条目,字段不多,但足够让我三个月后重新打开时能快速回忆起这道题的核心。四个必填项如下表:
| 记录项 | 写什么 | 为什么写 |
|---|---|---|
| 核心思路 | 用一两句话解释解法 | 逼自己把思路压缩成可复述的模型 |
| 卡点与错因 | 第一次做时卡在哪一步 | 卡点就是你的思维盲区,是复习的靶心 |
| 复杂度分析 | 本题最优解的时间与空间复杂度 | 形成了复杂度意识,面试不被动 |
| 同类题型 | 这道题属于哪一类套路 | 给题目分类,把点连成网 |
千万别小看第四项。我后来二刷时发现,我第一次做得磕磕绊绊的题目,往往不是因为难,而是因为我对“这一类题”缺少归纳。比如“滑动窗口”就是一个套路,不管题目包装成什么样子,核心都是维护窗内状态、判断窗口收缩条件;比如“区间合并”就是先排序再扫描,几乎可以机械解决。当你的笔记里能把题目按套路归类时,你就已经建立了知识体系,而不是一麻袋散装知识点。
四要素写起来很花时间,尤其前期,一道中等题可能要记十几分钟。我一度也嫌麻烦,直到我发现自己刷过的第80题在三个月后完全认不出来,才意识到这个时间省不得。你刷一百道题,如果每道题都是一次性记忆,那你的真实存量可能只有二三十道;花一半的时间记复盘,存量反而能到七八十道。
4.2 二刷三刷的时机:记忆曲线比意志力可靠
复盘不只是记录,还包括复习。我遵循的节奏很简单:一刷完成的第3天回顾一次思路,第10天到14天重新做一遍,第30天再做第三遍。第三遍仍然能做对并且能独立写出精简解法,这道题才算从“当过客”变成“自己人”。
最常被误解的是“复习=重看一遍代码”。重看没有用,关键是关掉题解、重新手打代码。我自己二刷时会给自己加一个条件:不看自己之前的笔记,纯靠记忆写出完整答案。如果写不出来,只能说明这道题你还没学会,老老实实回归第一遍的正常流程,再走一遍“看题解、合上重写、记卡点”的循环。这个过程很残酷,但也确实可靠。
4.3 题解区怎么读:不是看答案,是看那些你没想到的东西
很多人的做题流程是:不会做,翻题解,抄代码,提交过,完事。这是效率最低的用法。高水平地使用题解,至少要读三样东西。
第一,看代码之前先看思路文字和复杂度分析。力扣的题解很多只贴代码不解释,但也有不少认真写思路的文章,先看懂别人的推导链条,而不是先看代码本身。第二,重点关注和你自己思路“差一个关键步骤”的地方——那种“原来还能这样想”的瞬间,才是你真正的增量。第三,如果这道题有多个解法,至少浏览前两三种,不需要全部实现,但要用一句话概括每个解法的核心思想。
有一次我做一道有序数组题目,自己的解法是二分查找,写完提交后翻了翻题解,发现用双指针就能在线性时间内完成,两个点一对比,我才真正理解“二分降低复杂度,但双指针通常利用有序性消除一层循环”这句话。这种对比带来的收获,比自己多刷十道题还要大。
5. 工作之后的刷题时间战:见缝插针与整块时间
很多人私下和我说,刷题最大的障碍不是题目难,而是上班之后真的没时间。这个说法一半是真,一半是借口。我白天要上班,晚上回家还有一堆生活琐事,确实不可能再有学生时代那种整晚刷题的条件。但也正因为这样,我摸索出一套“碎片时间看轻量、整块时间做专项”的打法。
5.1 碎片时间的正确用法:不是打开app硬做难题
通勤、午休、排队,这类碎片时间一共可能有大半个小时。如果是新手,我建议不要试图用碎片时间完成一道困难题——思路刚建立起来就被打断,体验很差,而且很容易形成“我今天刷了题”的错觉。
碎片时间我主要做三件事。第一,读题解,挑一道标记过的中等题,在手机上看官方的思路分析,不写代码,只看思路。第二,回忆复杂度,随手翻自己笔记里记录的旧题,在心里默想解法思路与时间/空间复杂度,想不起来就点开瞄一眼。第三,背模板,把二叉树遍历、回溯、DP分析的框架在脑子里过一遍,就像背单词一样,每天过几遍,形成肌肉记忆。
这三件事听起来不起眼,但叠加起来力量不小。碎片时间最大的价值不是处理高难度认知任务,而是维持“手感温度”,让你在晚上坐到电脑前时,不需要花半小时热身就能进入状态。
5.2 晚上的整块时间:两小时只干一件事
以我自己的经验,下班后能从晚上九点挤出两小时已经非常奢侈,所以这两小时的使用原则必须是“高浓度”。我给自己定的规矩是:一个晚上只处理一个知识模块,绝不东一榔头西一棒槌。比如今天晚上是动态规划,那就是两道DP题,难度从简单到中等;明天晚上是图论,那就把DFS/BFS在图上的写法练透。
为什么这样安排?因为算法能力的提升是“局部强化”的过程,你在一个模块里连续浸泡,才能看清套路的变化。今天刷一道数组、明天做一道树、后天碰一道字符串,每个模块都浅尝辄止,大脑根本来不及归纳。反之,连续三晚都练回溯,你会明显地感到从“照抄模板”到“知道什么时候该用、怎么剪枝”的转变。
这里的另一个细节是,晚上的时间要刻意避开“难题陷阱”。白天已经很累了,晚上再做超出当前能力的困难题,往往会在前30分钟就耗尽精力,剩下的一个半小时就是无效挣扎。我的做法是:状态好的晚上冲一道困难,状态一般的晚上就老实刷中等题巩固。
5.3 周赛不是比赛,是给你设置截止日期
上班之后时间本来就碎,更容易把刷题拖成“有时间再做”的状态,这时候最需要的不是意志力,而是截止日期。每周日的力扣周赛就是现成的截止日期。
我不建议每个阶段都去参加周赛,因为前期的你可能连题都读不完,去了也是打击。但当你刷到150题左右时,周赛就变得非常有价值:它逼你在有限时间内完成和评分,还能真实暴露你在压力下读题、选算法、写代码、调试的能力。我参加周赛的主要目的不是排名,而是给每周的刷题设置一个“交付节点”,周赛结束后,根据自己的表现回看笔记,哪类题卡住了,下周就专项补哪类。
这种做法最实际的好处,是让刷题从“无限期任务”变成了“周期性交付”,它天然形成反馈闭环。即使某次周赛成绩很差,你也会得到一个非常具体的信号,知道自己接下来的七天该练什么。
6. 刷到中段之后的瓶颈与心态:这条路最难的其实是坚持
很多人的刷题之路不是倒在起点,而是倒在150到300题这段区间。这个阶段简单题已经刷腻了,明显的进展感消失了,动态规划又反复卡人,很多人因此开始怀疑自己是不是“不适合刷题”。我想说,这种感受太正常了,因为刷题曲线的中段就是最陡的一段爬坡,几乎所有人都会在这里经历平台期。
6.1 平台期的信号与对策,越早识别越好
平台期的信号其实很好辨认:一是打开题库划半天不知道做什么,二是简单的题看哪儿哪儿熟,中等以上的题看哪儿哪儿懵,三是刷完之后大脑一片空白,没有“我又学会了一样东西”的感觉。
我的应对办法是主动变轨。第一种变轨是“降维复习”,把之前做过的经典简单题重新做一遍,但不追求一次通过,而是追求写出最优解、写出多种解法。这能快速找回掌控感。第二种变轨是“换场景”,从按题库刷题切换到按专题刷题,用题单或者自己整理的同类型题列表,集中把一个方法吃透。第三种变轨是“允许暂停”,如果你连续一周都觉得分数没有进展、做题完全没有兴奋感,那就干脆把刷题停掉几天,去写写业务代码、做点其他事情,间隔期之后再回来,你会发现很多之前想不通的题目突然变得不那么可怕了。
平台期还有一个心理因素:人对“线性进步”有天然的期待,总觉得刷得越多就应该越强。但算法能力的增长更像台阶式,你可能在某个难度里停留很久,积累够了才突然上一个台阶。所以,如果两周内感觉毫无进展,不要急着自我否定,先检查自己是不是只在做已经会做的题目,如果是,那说明你该换难度了。
6.2 允许自己慢下来之后,反而刷得更快了
我刷到将近300题时,曾经做了一个非常反直觉的决定:每天只刷一题,有时候甚至两天才刷一题,但要求是这道题必须完全吃透,包括多种解法、复杂度、变体。很多人听到这个会觉得进度太慢,但实际上这三个月是我能力提升最快的阶段。原因在于,把刷题的速度降下来后,我有更多时间去归纳、去比较、去内化,把每个模块里的解题套路真正长到身上。
后来我重新提速时发现,很多之前要花四十分钟的中等题,现在十分钟内就能写出清晰解法。这种提速不是机械刷量带来的,而是对整个问题框架熟悉之后自然发生的结果。所以如果你正处于“刷了很多题但还是不会”的焦灼里,我真心建议你试试放慢,一周只攻一个模块,把每个模块的常见题型扫一遍,你会体会到什么叫厚积薄发。
6.3 工作之后,我为什么还在刷题
有段时间我经常问自己一个问题:如果近期完全没有面试需求,我还有必要保持刷题习惯吗?每一次我的回答都是一样的:有必要。不是为了某个具体流程,而是因为刷题带来的分析能力会渗透到日常的工作里。遇到复杂业务问题时,我下意识地会先抽象、再拆解、最后找最优方案,这个思考路径就是刷题训练出来的。
同时我也和很多长期刷题的朋友交流过,大家普遍有一个共识:这一行的技术栈三年一小变、五年一大变,但算法和数据结构是其中的“不变量”。练好它们,其他技术换得再勤,你也有底气去快速适应。
如果让我给刚踏上这条路的人一个最朴实的建议,那就是:今天不要纠结任何策略,打开力扣,挑十道简单题连续做掉,先让成就感出现。这条路很长,但每一步都算数,你刷过的每道题、写下的每篇复盘,都会在未来的某个时刻连点成线——就像我三年前深夜提交的第一道题,当时只觉得挫败,现在回头看,那正是整条路的起点。