ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LeetCode面试经典150题60天刷题总结:算法面试准备与刷题顺序全攻略

LeetCode面试经典150题60天刷题总结:算法面试准备与刷题顺序全攻略

刷到第60天,正好是1月19号这天。LeetCode面试经典150题单,我从大概11月底开始啃,中途断断续续、反复回退,今天终于把这150题完整过完第一遍。说“过完”,不是说每道题都能一遍秒杀,而是所有题都至少动手写过、整理解过思路、记录了错误点。这份题单在准备技术面试的人里几乎人手一份,但它到底适合谁、该用什么顺序刷、卡住了怎么处理,真正说得清楚的并不多。这篇文章就把我60天的实际过程拆开来讲,希望能给正在刷题或准备开始的人一点参考。

1. 为什么是“面试经典150”而不是其他题单

1.1 这份题单和其他题库的区别

市面上的刷题资源无非几类:按知识点分类的专项练习、公司高频题汇总、竞赛真题,还有LeetCode官方出的面试经典题单。我一开始也纠结过到底刷哪个,后来选了“面试经典150”,核心原因是它的分类结构最适合面试场景。

这份题单把150道题按知识点切成块:数组/字符串、双指针、滑动窗口、矩阵、哈希表、区间、栈、链表、树、二叉树、图、回溯、分治、Kadane算法、二分查找、堆、位运算、数学、动态规划。注意它把树和二叉树分开列,动态规划放在最后面,说明官方是从面试出题频率和认知难度两个维度排的。相比之下,“热题100”更偏高频但题目之间没有清晰的训练主线,刷完容易“见一道会一道,换一道就懵”。“面试经典150”更像一套教材,每个知识点给足典型题,刷完能自然建立解题框架。

我个人的判断是:时间紧张、只剩两周突击面试的人,先去刷高频题更划算;但如果是还有一两个月准备时间,想把算法基础真正补到能应对大多数面试题的水平,150题是最合适的性价比选择。

1.2 60天的进度安排和阶段划分

一天刷2到3道题,加上复盘,大概需要两个小时。这是比较稳的节奏。我见过有人一天刷10道,但那样基本是看题解背代码,过几天全忘。我的60天大致分成三个阶段:

  1. 前15天:主攻数组、字符串、双指针、滑动窗口、矩阵、哈希表。这类题是算法题里的“基础代谢”,几乎每场面试都会碰到,而且很多复杂题的本质就是“数组+哈希”的组合。
  2. 中间25天:主攻链表、树、二叉树、图、回溯。树和图是面试官最爱的题型,代码量大、递归思维要求高,需要整块时间反复练习。
  3. 最后20天:主攻二分查找、堆、位运算、数学、动态规划,以及之前标记出来的难题回炉。

刻意把动态规划放最后,是因为它需要前面积累的数组遍历、递归、状态分析能力作铺垫。上来就刷DP容易劝退。

2. 刷题顺序和知识点的重要性排序

2.1 高频题型金字塔

如果把这150题按面试出现概率排序,我个人会排成这样:

优先级知识点典型特征面试中出现概率
第一梯队数组、哈希表、双指针、滑动窗口代码量适中,边界条件多几乎每场必考
第二梯队二叉树、链表、图、回溯递归和遍历思想为主约70%的面试会涉及
第三梯队动态规划、二分查找、堆有固定套路但需要大量练习约40%的面试会涉及
第四梯队位运算、数学、前缀和、区间题型相对固定偶见,但考到就是拉开差距的题

这个排序和我刷题前的预期不太一样。我原来以为动态规划是最重要的,实际刷下来发现,二叉树和回溯才是区分选手的关键。原因很简单:动态规划题目特征明显,看到“最多”“最少”“方案数”基本能往DP上靠;而二叉树题可以伪装成各种形态,比如“验证二叉搜索树”“最近公共祖先”“二叉树的序列化”,识别不出递归模型的人会毫无头绪。

2.2 核心章节的刷题重点

数组和双指针是地基。这个部分我刷得最细,因为后面几乎所有题目都隐含了数组思维。比如“接雨水”这类题,表面是双指针,实际还可以用单调栈、动态规划做,一题练三个思路。滑动窗口的题目则要重点掌握“窗口何时扩张、何时收缩”的判断逻辑,这里最容易漏边界。

二叉树是重头戏。递归三步法几乎能解掉大部分题目:先确定递归函数的参数和返回值,再确定终止条件,最后写单层递归逻辑。我当时把每道树题都强制按这个模子写,写多了以后,看到二叉树题目第一反应不再是害怕,而是先条件反射地把三个步骤列出来。

动态规划的练习重点不在“状态转移方程怎么来”,而在“怎么证明它是错的”。一个DP写法提交之后,如果没过,不是状态定义出问题就是转移漏了情况。我把每道DP题的失败提交都留档,后发现最常见的错不是复杂的优化问题,而是数组下标越界、初始状态没赋好这种低级错误。

3. 60天里最值得反复刷的几类题目模式

3.1 双指针与滑动窗口的模板化写法

双指针类题目,我在60天后总结出一个通用思考框架:

  1. 先问自己:这个数组/字符串是不是有序的?如果有序,左右指针大概率能用。
  2. 再问:题目要求的是连续子串/子数组吗?如果是,考虑滑动窗口。
  3. 最后问:能不能用空间换时间?用哈希表记录已经出现的数据是关键。

以滑动窗口为例,我的固定模板是:

left = 0 for right in range(len(nums)): # 扩张窗口,更新状态 update(right) # 当窗口不满足条件时,收缩左边界 while invalid_window(): remove(left) left += 1 # 记录结果 record()

这套模板解决“无重复字符的最长子串”“最小覆盖子串”这类题时特别好使。关键窍门是:每次只处理一个右端点的扩张,左端点只在条件不满足时才动,这样不会乱。

双指针的核心细节更多。比如判断回文串时,指针移动要跳过非字母数字字符;三数之和要去重,指针移动时不仅要保证left < right,还要跳过与上一次相同的值。这些细节我在前两次提交里全踩过,到后面形成肌肉记忆了。

3.2 回溯和二叉树是递归思维的试金石

回溯算法的题目数量不算多,但变化很丰富,从排列、组合、子集到棋盘问题、单词搜索,都是同一套逻辑。我把它总结成模板:

def backtrack(路径, 选择列表): if 满足结束条件: 记录结果 return for 选择 in 选择列表: 做选择 backtrack(路径, 新的选择列表) 撤销选择

这个模板帮我拿下了所有回溯类题目。真正容易出错的是“去重”和“剪枝”。排列问题要用used数组记录哪些元素用过了,组合问题去重要先排序再判断相邻元素是否相同,棋盘问题要在递归前判断是否越界。我把常见的去重场景整理成了一张速查表,贴在笔记里,回看时非常方便。

二叉树题目我没有用统一模板,而是按照遍历顺序分类练习。前序遍历适合“从上到下构建”,中序遍历在二叉搜索树里有天然的有序性,后序遍历适合“从下往上返回信息”。一旦能够根据题目要求快速选择遍历顺序,树题就成功了一半。

3.3 动态规划的“五步法”练习

动态规划我刷了两轮。第一轮只求能看懂题解,第二轮要求自己独立推导。我用的还是业界常见的“五步法”:

  1. 定义dp数组的含义(下标、状态)
  2. 推导状态转移方程
  3. 初始化dp数组
  4. 确定遍历顺序
  5. 打印dp数组检查是否与预期一致

其中最容易翻车的是第一步。很多题看似能用“一维dp[i]”解决,实际状态有两个维度。比如“编辑距离”“最长公共子序列”必须用二维dp;“单词拆分”虽然是一维,但需要配合哈希表查词。所以每拿到一道DP题,我会先把“状态”用中文完整写一遍,再写代码。这个习惯帮我减少了很多无效提交。

4. 实际的刷题流程、代码习惯与提效工具

4.1 一道题的标准处理流程

我给自己定的流程是:

  1. 读题后,先不急着看题解,自己尝试设计暴力方案,哪怕复杂度很高也要写出来。
  2. 在暴力解基础上思考优化点,比如能否用哈希表替代两层循环、能否用双指针减少一层循环。
  3. 独立思考30分钟,有思路就直接动手写;没思路就标记为“卡题”,当天看题解,但第二天必须不看题解重写一遍。
  4. 提交通过后,去题解区看一两个高票思路,找出比自己解法更优的方案,把差异记录到笔记里。
  5. 每周固定抽出一天,专门重刷本周记录中标记为“第二次才能写对”的题。

这个过程很慢,但很有效。刚开始一天只能完完整整走完一遍流程的两三题,到后面熟练了,一天能处理四题,因为很多题目套路相同。

4.2 代码习惯和复杂度意识

刷题过程中,代码风格同样重要。我在60天里逐渐固定了一套习惯:

  • 变量名尽量用有意义的词,而不是i、j、k满天飞。写left、right比写l、r更容易在思考时降低认知负担。
  • 每个函数开头先处理边界情况:空数组、空字符串、只有一个元素、nums长度为1。
  • 提交前强制自己算一遍时间复杂度和空间复杂度,写在注释里。面试时这一步几乎是必问题。

有一类错误我反复栽跟头:Python里的浅拷贝问题。列表直接赋值给结果数组,后续修改原列表时会连带修改结果。比如子集、排列类题目,记录结果时必须写result.append(path[:]),不能直接append(path)。这种坑不看题解很难发现,属于典型的环境特性坑,我后面统一用深拷贝快照的方式解决了。

4.3 我用到的提效工具

我不太推荐过度依赖插件和可视化工具,但下面几个对我的帮助确实很大:

  • 本地笔记软件按知识点建页,每道题记录:题目链接、我的思路、复杂度、第一次错误点、最优解法的思路。
  • 刷题平台的提交记录自带统计功能,我每周看一次“通过率最低的知识点”,就知道接下来一周该补哪里。
  • 用Markdown维护一份“模板速查表”,收录双指针、滑动窗口、回溯、二分、树的遍历等常用模板,复习时只看这份表。

5. 卡题、遗忘、心态崩塌:60天里踩过的坑和应对方法

5.1 卡题的正确打开方式

卡题太正常了。150题里我独立做出来大概只有70来道,其余全是看题解后理解的。卡题并不可怕,可怕的是“硬扛时间”。我以前刷题有个坏毛病,一道题没思路就死磕一两个小时,最后又累又挫败。后来调整成“30分钟无思路就看题解”,效率高了很多。

看题解也有讲究。菜鸟是抄代码,老手是看思路。我通常先看题解的“思路描述”部分,不看代码,然后关掉题解自己动手写。如果仍然写不出来,再回来看代码,看完后把题目标记为“需要隔天重写”。这么做能避免“眼睛会了手不会”的虚假满足感。

5.2 对抗遗忘的策略

60天跨度足够长,遗忘是必然的。我在第20天回头看前几天刷过的数组题,发现很多解法已经想不起来了,当时很崩溃。后来我用了两个办法:

第一,滚动复习。每天刷新题之前,花10分钟快速浏览前一天做过的题和笔记,不重写代码,只看思路。刷到第50天时,我已经能用10分钟过完前10天的所有题目。

第二,模式归类。与其记“哪道题怎么做”,不如记“哪类题用什么框架”。比如看到“两个有序数组求中位数”,核心是二分排除法;看到“最长递增子序列”,先想贪心+二分能不能做,再想DP。把题目抽象成模式,遗忘速度会慢很多。

5.3 时间不够时的取舍

如果只剩两三周就要面试,我会做三个取舍:

  1. 果断放弃“困难”级别里偏门题,比如某些需要高级数据结构的题目,宁可留着时间巩固二叉树和DP的基础题。
  2. “中等”难度题优先刷,因为面试考察最多的就是中等题。
  3. 每题只追求“能讲清思路”而非“最优解”。面试里最常见的情况是,面试官并不要求你一次写出最优解,而是想看你能不能从暴力优化到更优方案。这时候过程比结果重要。

5.4 常见问题速查表

现象原因解决办法
思路正确但提交超时Python循环太慢,或复杂度比预期高检查是否有重复遍历;考虑用哈希表/双指针降维;少数情况用sys.stdin优化IO
输出结果与实际不符边界条件漏处理先补空输入、单元素输入;打印dp或窗口状态
递归栈溢出终止条件缺失或递归深度过大检查终止条件;大型数据优先考虑迭代写法
数组越界指针移动没加边界判断在访问索引前先判断上下界,尤其在while循环里
答案正确但内存超限创建了多余的大数组用滚动数组、原地修改、位压缩
“看题解能懂,自己写不出来”只是视觉记忆隔天重写;把题解思路用自己的话写在笔记里

5.5 独家避坑清单

最后分享三个我在第40天之后才悟到的经验:

  • 题目会做和能表达是两回事。刷到后半程,我每周抽两三天,用口述方式把解题思路讲给自己听,模拟面试表达。很多刷题多的人挂在表达上,代码写对却说不清为什么,这在面试里非常吃亏。
  • 难度高的题对代码量的要求未必高,很多时候二十行以内就能解决。如果发现自己写了六七十行还没完成,大概率是思路偏了,停下来重想。
  • 别在刷题数量上自我感动。day60这个节点,比进度更重要的是复盘质量。我做过最亏的一件事是连续三天猛刷新题,结果把前面积累的模板全忘了。定期的回溯比推进度更重要。

6. 这是60天的答案,不是终点

费了60天刷完这150道题,说句实话,到了最后几天,我的刷题速度已经上来了,但心态反而更谨慎。因为刷得越多,越知道自己不知道的还有很多。比如有些题我虽然能过,但要我讲清楚证明过程还是有点虚;有些DP的状态压缩写法,我还在练习。这份150题更像一份“地图”,刷完第一遍,我总算能看清地图上的主干道了,接下来要做的就是把主干道跑得更熟。

如果你也正在刷这份题单,或者正要开始,我建议你把“刷完”当成一个起点而不是终点:一边刷一边整理自己的模板库,定期回头重做错题,多给自己模拟面试表达的机会。一个月后你再回头看60天前的自己,会明显感觉到算法思维上了一个台阶。这个感觉,远比那个“day60”的打卡数字更有价值。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进