
今天是我在力扣刷题的第60天日历正好停在1月19日。60天前我在题单收藏夹里翻出“力扣面试经典150题”点开第一题的时候还想着“150题不算多一天五道一个月搞定”结果第一周就被数组哈希的题目教做人。现在把整份题单完整过完再回头看那些曾经卡到怀疑人生的题最大的感受不是“我会写了”而是“我终于知道算法面试到底在考什么”。这篇内容不是那种“教你怎么刷题”的鸡汤文而是一个普通程序员60天刷完150题之后踩坑、调整、复盘的流水账。里面有我的三轮刷题计划、每日时间分配、每类题型的啃法以及刷题过程中遇到的心态问题。如果你刚开始刷这份题单或者刷到一半感觉进度推不动、刷了忘、忘了刷那这篇内容应该能给你一点参考。1. 为什么我把这150题当作刷题主路线1.1 一份人工筛过的“考点地图”刚开始准备算法面试的时候我其实犹豫过是去题库里按“题号”从1刷到1000还是按“Hot 100”刷还是直接上这150题。后来我选了后者原因是这份题单的题目结构很像一张考点地图。它不是把题库里的题简单堆在一起而是按数据结构与算法主题做了分层数组/字符串、双指针、哈希表、矩阵、滑动窗口、模拟、区间、栈、链表、树、图、回溯、分治、二分查找、堆、位运算、数学、动态规划还有多维动态规划。我数了一下这份题单里的题覆盖了大约20个左右的算法主题。每个主题下面少则三题多则十几题不是随机抽题而是按照“先基础后进阶”的方式排列。比如数组相关的题目从“两数之和”这类入门题开始逐步过渡到需要思考边界条件的滑动窗口题、需要巧妙解题思路的区间合并题。这种编排方式相当于有人已经帮你把剑法招式拆好你只需要按顺序练就行。相比从题库里按题号刷或者只挑高难度题硬刚这套题单最大的优势就是它把时间和精力优先分配给了高频考点。刷完之后就算遇到没见过的题心里也有个底——无非是哪几个模板加哪几个变形。1.2 和盲目刷题相比它到底赢在哪里我知道很多人刷算法的习惯是“先做十道链表题再做十道树题”或者干脆按通过率从高到低刷。这种刷法不是不行但容易踩三个坑第一没有优先级刷着刷着就去刷那些偏难怪的题浪费大量时间第二重复劳动其实很多题是同一个套路的不同马甲盲目刷会导致同样的代码写了十几遍第三没有进阶路径容易在某个难点上死磕比如我一开始死磕动态规划结果基础题还没吃透就去看背包九讲看完直接想放弃。150题给了一条明显的坡度线。前三分之一是数组、字符串、双指针、哈希这类“热身题”中间三分之一是链表、栈、树、图的“结构题”后三分之一才是回溯、动态规划、贪心这些“分水岭题”。这条坡度线不是随便定的我刷到后期明显发现动态规划题里需要用到的“状态定义”思路在早期的二维矩阵题里就有雏形图的BFS模板和二叉树的层序遍历模板几乎一模一样。先刷前面的题后面自然就顺了。2. 60天刷题节奏与每日时间分配2.1 我的三轮滚动计划拿到题单之后我没有按照“每天5道30天刷完”这种计划走因为以我的水平一天5道新题根本消化不了。我最后用的是三轮滚动计划60天刚好走完三轮。轮次时间段日均题量核心目标刷题方式第一轮第1-15天2-3题建立知识框架按标签顺序刷每题独立写思路第二轮第16-40天3-4题跨主题混合训练打乱标签刷强制调用模板第三轮第41-60天4-5题错题重刷与专项补弱只刷错题、重点题和变形题第一轮的前15天我老老实实跟着题单的顺序走。因为题目按主题归类很多题之间思路是相通的刚开始刷会特别有成就感做完一道“最大子数组和”再去做下一道同主题的题基本上能套上思路。这阶段的目标不是“速度”而是“建立索引”——每刷一类题脑子里要有这张主题下大概有哪些常考题型。第二轮我开始乱序刷把经典150题切成小块每天从不同标签里各取一题。这一步很关键因为面试不会告诉你“这题考的是双指针”再让你做必须学会自己从题目描述里推断考点。乱序刷会明显感觉到难度提升但也真正检验出哪些题你是背下来的哪些题你是理解了的。第三轮重点就是错题。我把所有刷过的题里第一次没过、或者看题解才做出来的题全部收集起来大概四十多道。每天五六道用白纸把解题思路默写一遍再重新提交代码。错题重刷的效率比刷新题高得多因为每一道都是自己真实漏掉的漏洞。2.2 每天的时间块怎么拆我每天的刷题时间基本稳定在90分钟到120分钟工作日晚上保证一个整块时间周末会多加一小时。这里我用的方法是“60分钟刷题法则”就是每道题最多分配60分钟拆成三段30分钟独立思考10分钟看题解20分钟总结提交。30分钟独立思考这个数字不是拍脑袋定的。经过前几周的测试我发现15分钟太短很多题刚有思路还没理清边界就到时间了45分钟又会陷进去一道题卡太久后面的计划全部打乱。30分钟刚好是一个临界点能让我把能想到的思路都想一遍又不会浪费太多时间。如果30分钟没有任何可行方向我就直接看题解——注意是“看思路提示”不是“抄答案”。10分钟看题解的时间里我只看别人的解题思路和复杂度分析不盯着代码看。实在想不出来的时候才看代码片段里最关键的那几行。20分钟用来写码、提交、处理边界条件。不要小看这20分钟很多题看懂思路和写对代码完全是两码事。卡在边界条件上的时间往往比思考算法本身还长。2.3 阶段自测怎么安排刷题最忌讳的是“一直刷从不考”。我每15天安排一次阶段自测第15、30、45、60天各一次。自测的方式比较简单从已经刷过的题里随机抽三个不同主题的题手机定时40分钟像模拟面试一样写。不能翻之前的笔记不能暂停时间到了就停笔。这个方法听起来简单但效果出奇地好。第15天的自测我就翻车了抽到一道树的中序遍历题明明刷过类似的但在40分钟的压力下递归函数都写不利索最后改了四五遍才通过。这次自测让我意识到平时刷题时“想一会再说”和面试时的“40分钟必须输出”是完全不同的状态。第30天之后每次自测的题目我会故意抽一道第二轮里做错的题检测自己是不是真的把漏洞补上了。这么做的好处是每次自测都相当于一次小小的模拟面试能让你在真实面试时不会觉得40分钟太短。分享一个技巧自测之后一定要给这次表现打分从思路、实现、边界条件、时间四个维度各打1到5分最后阶段对比看有没有提升。3. 150题里的核心题型我按这个顺序啃3.1 数组、哈希表、双指针热身与节奏感数组和哈希属于“看起来简单写起来要命”的题型。比如“两数之和”的暴力解法是O(n²)但用哈希表一次遍历就能到O(n)这类题的核心就是“空间换时间”这个思路。刷这类题我最大的心得是不要满足于“过题”要强迫自己想一下如果有进阶条件怎么办。比如数组有序能不能用双指针输出所有组合而不是一对组合该怎么改有没有重复元素怎么去重。双指针是150题里一个高频主题。它分两种一种是对撞指针用于有序数组寻找两数之和、反转数组这类核心逻辑是左右指针根据当前结果决定移动方向另一种是快慢指针用于链表找环、数组去重。对撞指针的题比如“盛最多水的容器”核心是理解“移动哪边的指针会导致结果怎么变化”这比记住代码重要得多。滑动窗口本质上也是双指针的变种窗口右边界往右扩左边界根据条件往右缩模板就那几行难的是想清楚窗口扩张和收缩的条件。3.2 链表、栈与单调栈结构题的套路链表题是“会者不难难者不会”的典型。它考的不是算法思维而是对指针操作的熟练度。150题里链表题的原型就是那么几个反转链表、合并链表、找中间节点、判断环、删除节点。每一个都有套路。比如反转链表用迭代法时记住三行核心保存下一节点、断开当前节点的next并指向前驱、移动cur指针。用递归法就记住假设以head.Next为头节点的链表已经反转好了现在要做的是head.Next.Next指向head再断掉head.Next。链表题里有个很重要的技巧叫“哑节点”dummy node。凡是涉及删除头节点、在头节点前插入节点的操作我都先创建一个空节点连上原链表最后返回哑节点的next。这一个小技巧能省掉大量特判代码如果你看别人的题解时发现他代码特别干净十有八九用了哑节点。栈和单调栈这边我最开始只会用栈做括号匹配直到刷到“每日温度”“柱状图中最大的矩形”这类题才真正理解单调栈的价值。单调栈的核心思想是维护一个栈内元素有序的栈在元素入栈时弹出那些“不满足单调性”的元素从而快速找到“离我最近的比我大/小的元素”。这类题背诵模板解决不了问题最好自己手动画一遍栈的入栈出栈过程搞清楚栈顶是什么、弹出后得到的结论是什么。3.3 二叉树、图与DFS/BFS树形思维练起来二叉树是150题里的重头戏题量不小。树题最大的特点是所有题的解法都围绕“遍历”。只要把前序遍历、中序遍历、后序遍历、层序遍历四种遍历方式写熟一半的树题都能解。比如求二叉树的最大深度就是后序遍历先算左子树深度再算右子树深度取最大值加一判断两棵树是否相同就是同时前序遍历两棵树每个节点都比较一次。很多树的题看起来很难实际就是把一个遍历模板改几行。图的部分是很多人的心理阴影但它和树的层序遍历其实是同一套东西。树的层序遍历用队列图的BFS也用一个队列加一个visited数组多了“防止重复访问”这一步。150题里有几个典型的图论题比如岛屿类问题核心就是找到一块陆地然后BFS或者DFS把整块岛标记出来再统计个数。刷完这些题之后我对DFS和BFS的适用范围有了更清楚的认识DFS适合“路径存在性”问题BFS适合“最短步数”问题。3.4 回溯、动态规划与贪心真正的分水岭如果前面的题是热身和积累那回溯、动态规划和贪心就是真正的分水岭。150题里这部分题明显提高了一个难度也是让很多刷题者中途放弃的地方。回溯算法的本质是“暴力枚举的优雅版本”核心是“选择、递归、撤销”三件套。比如全排列、组合总和、子集这些题模板高度一致先判断终止条件然后把候选列表里的元素一个个加入当前路径递归调用调用结束之后把最后一个元素从路径里撤销。这个模板看起来简单但实际刷题时最常犯的错误是忘记撤销或者撤销的位置写错导致结果多出很多重复组合。我建议每写一道回溯题都在纸上画一棵“决策树”把哪些分支该剪掉标注清楚而不是上来就写代码。动态规划是150题里最考验抽象能力的题型。我自己的学习路径是先刷经典的“爬楼梯”类一维DP再刷“不同路径”类二维DP最后才碰“编辑距离”这类多维DP。不管什么题我都会严格执行一套“DP五步法”定义dp数组的含义、写出递推关系、初始化边界条件、确定遍历顺序、手动推导一遍dp数组的前几个值验证。这套方法看起来很笨但它是唯一一种能让我从“看了答案恍然大悟”变成“下次能自己想出来”的方法。贪心题在150题里的数量不算多但普遍短小精悍。贪心的核心是“每一步都做当前看起来最优的选择”难点在于证明这个选择是正确的。刷题阶段我不会去严格证明每个贪心解法的数学正确性那样太费时间。我的策略是先用几个典型例子验证直觉再想想能不能举出反例如果举不出来就先按贪心写错了再看题解。3.5 位运算、数学与其他杂项别放在最后位运算题在面试里出现频率不高但一旦出现就是“要么秒、要么死”的类型。150题里的位运算题属于必拿分项因为套路特别固定异或可以用来找出现一次的数字n (n-1)可以清除最低位的1与掩码配合可以获取某一位的值。我建议把这些位运算技巧整理成一个速查表刷之前先背一遍刷的时候就不会一头雾水。数学类题包括质数计算、快速幂、最大公约数、找规律等。这类题没什么通用模板但很多都有现成的数学结论。我一般不强求自己当场推导而是看完题解理解之后记住结论重点记住“什么特征的问题对应什么数学方法”。比如看到“大数幂取模”直接想到快速幂模板看到“寻找缺失的数”可以想到等差数列求和公式或者异或。不要把这类杂项题放在计划的最前面刷容易打击信心。放最后当成甜点题刷反而能调剂心情。4. 刷题过程中的实操心得4.1 独立思考时间到底该撑多久我在前文已经说了每道题先独立思考30分钟。这里再补充一个细节如果30分钟内想到了一个可行思路但没把代码写完我会继续写不设上限。因为“有思路但写不出来”通常不是思路的问题而是实现细节不够熟练这种时候写下去才有收获。反过来如果30分钟完全没有方向就不要死磕了。死磕半小时以上心态会明显发生变化后面几道题都会受影响。看题解也有技巧。不是把别人的代码从头到尾读一遍就完事而是先看题解的“思路说明”自己尝试补全代码补不出来再看代码里对应的循环条件、边界判断。这样一道题看下来虽然花的时间多一点但脑子里的影子比直接抄一遍深得多。4.2 把“能过的代码”升级成“自己的模板”刷到第20天左右我意识到一个事实很多题我虽然过了但过几天再让我写代码会写得跟第一次不一样甚至会写出更啰嗦的版本。原因是我没有把解题过程沉淀成模板。后来我搞了一个“算法模板本”每类题只保留一种我认为最优的写法统一变量命名统一边界处理方式。以二分查找为例网上流传的模板有好几种有的用左闭右开有的用左闭右闭有的用while(lr)有的用while(lr)。我在模板本里固定了一种写法左闭右闭区间while(l r)mid l (r - l) / 2然后根据条件收缩l或r。这个模板虽然看起来稍显啰嗦但它不会出现死循环和越界。之后遇到所有二分题我第一件事就是把题目的逻辑套进这个模板而不是现场想“落边界条件怎么处理”。树遍历也是同样的道理。我把前序、中序、后序、层序的统一写法都背了下来每次遇到树题直接套。很多新手觉得背模板很死板但刷题不是创作是在有限时间里稳定输出正确答案。自己的模板背得够熟面试时就能把大脑算力留给真正的思考。4.3 错题复盘和写单元测试一样认真很多人刷题是“错题看一遍题解就过去”我前15天也是这样结果第16天的自测直接翻车。于是我从第二轮开始建立了错题三行记录法错误原因、卡住的点、下次怎么避免。举例说明有一道动态规划题我的错误原因是dp数组定义错了用了“前i个元素的最大值”但题目要求的是“以第i个元素结尾的最大值”定错了dp数组递推关系自然全部写错。卡住的点在于“不知道dp[i]到底该代表什么才能递推下去”。下次怎么避免拿到DP题先假设dp[i]表示“前i个”再验证递推时能否用到dp[i-1]的信息用不了就换“以i结尾”试试。把这一类错误记录下来之后后面再遇到DP题我会主动在“前i个”和“以i结尾”两种定义之间切换尝试不再傻傻地盯着题发呆。错题本不是抄题而是记录“思维断点”。我每道错题只记录三行以“下次遇到类似题我应该怎么做”结尾。这样到第三轮重刷错题时每一题一眼就能看到当时的坑在哪。4.4 复习间隔我实测下来最有效的节奏刷题最痛苦的事情是什么刷了忘。第20天做过的题第35天再见到可能已经完全没印象。我试过每天抽时间复习旧题效果一般因为占用了太多刷新题的时间。后来我用了“1-3-7-14-30”复习法也就是一道题做完之后的第1天、第3天、第7天、第14天、第30天各复习一次。复习时不是重写整个代码而是做三件事看一眼题目立刻在脑子里冒出的解题思路是什么对照当时的错题记录确认这个思路是否覆盖了之前的坑如果思路顺畅就跳过代码如果卡壳就重新写一遍代码。我用这种方式每天大概只需要额外花20分钟复习但旧题的记忆留存率比每天都翻一遍更稳定。这个方法也适用于日常工作学习中本质上就是利用遗忘曲线做间隔重复。5. 刷题常见问题与排查实录5.1 题目看懂了就是写不出代码这个问题我前两周特别频繁。看着题目心里明明有想法但一到代码层面就卡住了。后来排查了一下原因大概分成两类一类是对编程语言的数据结构和API不熟比如不知道还有Deque接口、不知道字符串转字符数组的方法另一类是刚开始写代码就没有框架意识想到哪写到哪写到一半自己把自己绕晕。排查方法如果是API不熟最快的解决方式是先去熟悉语言标准库写几个小的demo练手不急着刷题。如果是框架意识问题就要强制自己在写码前先写一个“伪代码框架”定义一个什么数据结构、循环条件是什么、循环体里三步是什么——写清楚之后再填充具体代码。坚持十道题之后这个习惯就能建立起来。5.2 刷过的题过两天就忘了我前面提了遗忘曲线式的复习法这里再多说一点忘记不是因为你笨而是因为大脑没有给这道题建立足够多的连接。每次刷完一道题最好在当天睡前用一分钟口述这道题的核心思路哪怕是对着空气说。说出来的过程会强迫你整理思路比默默看一遍管用得多。如果哪道题连复习三次都还是忘把它单独挑出来放在“高频遗忘清单”里每周末只看这些题。到了第三轮我的高频遗忘清单从最初的20题降到了8题这8题成了我考前最后一天的重点。5.3 一天刷太多效率下降有一天我心血来潮一口气刷了10道新题当时心里特别满足觉得自己要起飞了。结果第二天做题时前一天的很多细节都已经模糊等于白刷。后来我把“日均题量”从“新题数量”改成了“新题复习题混合数量”每天新题最多3道其余时间用来重写旧题模板。看起来进度慢了但知识留存率高了整体走下来反而比贪多更快。我的亲身体验是刷题这种需要高强度思考的活动大脑一天能高质量处理的“新问题”数量是有上限的。超过这个上限后面的题目基本是在机械敲代码完全达不到训练效果。如果你白天上班已经很累晚上刷题时发现看三遍题都看不进去那就不要硬扛改变复习旧题或者直接休息。5.4 心态崩了怎么办刷到动态规划和图论那几周我的情绪经历了大幅波动。每天都觉得自己是个废物50行的回溯代码改了很久还是输错样例一度想直接把计划砍掉。后来我从一位朋友那里听到一个建议把“我为什么这么笨”换成“我离答案还差哪个点”。这个句式转换真的有用因为它把负面情绪转移到了具体问题上。每次写不出来我就按这个句式一句句往下拆差哪个点差在状态转移没想清楚。为什么没想清楚因为dp数组定义错了。怎么定义才对用“以i结尾”试试。当拆到这一步的时候代码往往已经快写完了。另外心态不好时不硬刷难题也很重要。我会切回简单题找找手感或者去重刷早期做过的第一轮题体验一下“这题我居然秒了”的成就感。刷题是长跑不是冲刺起伏非常正常没必要因为一两次失败就否定前面的努力。到今天这份150题已经被我完整过了一遍。回看第1天到第60天的记录最大的变化不是我背下了多少题而是遇到一道没见过的题时我不再觉得慌我会先去判断它的数据结构特征再去匹配双方框里已经整理好的模板。这就是60天带给我最实在的收获。如果你也在刷这份题单还没到60天别着急按照自己的节奏往下走。到了我这个进度再回头看第10天时的自己你真的会觉得那点痛苦都不算什么。