1. 刷题汇总这件事,到底该怎么理解
LeetCode刷题汇总,说白了就是把一段时间内做过的题目,按照某种逻辑重新梳理一遍,把散落的知识点串成线、连成面。很多人刷题刷了几百道,遇到新题还是发懵,根本原因就是缺少汇总这个环节。我自己从零开始刷题那会儿,也是做完一道丢一道,下次遇到同类题换个马甲就不认识了。后来逼着自己每刷完一个专题就做一次汇总,效果立竿见影。
这篇汇总面向的是正在刷题路上摸索的朋友,不管你是刚接触LeetCode的新手,还是已经刷了几百道但感觉遇到瓶颈的老手,都能从中找到可参考的思路。我会把汇总的方法论、具体操作步骤、常见坑点都拆开来讲,尽量做到你看完就能动手整理自己的刷题记录。
核心关键词就一个:汇总。但汇总不是简单地把题目列个清单,而是要提炼出每道题背后的解题模式、数据结构选择逻辑、边界条件处理方式,以及同类题之间的迁移关系。这四样东西才是汇总的真正价值所在。
2. 为什么要做刷题汇总,不做行不行
2.1 刷题不汇总的典型症状
先说说我观察到的、以及我自己踩过的坑。刷题不汇总的人,通常有以下几个表现:
- 同一类型的题目,换个问法就不会了。比如昨天刚做了“两数之和”,今天遇到“三数之和”就卡壳,明明核心思路是相通的。
- 做题全靠肌肉记忆,题目稍微变形就失效。比如二分查找,写惯了标准模板,遇到“查找第一个大于等于目标值的元素”就不知道怎么改。
- 面试时被追问“还有没有更优解法”,大脑一片空白。因为平时做题只求AC,没有横向对比过不同解法的优劣。
- 刷题数量上去了,但信心没上去。每次打开新题还是心虚,感觉自己像在碰运气。
这些问题的根源都一样:知识没有结构化。刷题的本质是建立一套解题的思维框架,而不是积累一堆孤立的题目答案。
2.2 汇总带来的三个实际收益
我自己坚持做汇总之后,最明显的收益有三个。
第一个是识别速度变快。拿到一道新题,扫一眼就能判断它属于哪个大类,该用什么数据结构,时间复杂度大概能压到多少。这种直觉不是天生的,是靠汇总时反复归类训练出来的。
第二个是解法迁移能力增强。比如我把“滑动窗口”这个专题汇总完之后,再遇到“最小覆盖子串”“无重复字符的最长子串”“找到字符串中所有字母异位词”这类题,基本能条件反射地想到用双指针加哈希表来维护窗口状态。
第三个是面试表达更清晰。面试官让你讲思路的时候,你能从“这类题的一般解法是什么”“为什么这里选这个数据结构”“边界情况怎么处理”三个层面去说,而不是干巴巴地背代码。
2.3 汇总的时机和频率
我的建议是:每刷完一个专题就做一次小汇总,每刷完一百道题做一次大汇总。小汇总聚焦在专题内部,把同类题的共性和差异列清楚;大汇总则跨专题,看看不同专题之间有没有可以互相借鉴的思路。
频率不用太高,但一定要坚持。我试过攒了三百道题再回头汇总,结果发现前面做的题忘得差不多了,汇总效率极低。后来改成每十道题就花二十分钟整理一下,反而轻松很多。
3. 汇总的具体操作流程
3.1 第一步:建立题目分类体系
汇总的第一步不是写代码,而是分类。我自己的分类体系是这样的:
| 大类 | 子类示例 | 核心考察点 |
|---|---|---|
| 数组与字符串 | 双指针、滑动窗口、前缀和 | 索引操作、边界处理 |
| 链表 | 反转、合并、环检测 | 指针操作、虚拟头节点 |
| 哈希表 | 计数、去重、映射 | 键值设计、冲突处理 |
| 栈与队列 | 单调栈、优先队列 | 顺序维护、延迟处理 |
| 树与图 | 遍历、最短路径、拓扑排序 | 递归、队列、并查集 |
| 动态规划 | 背包、区间DP、状态压缩 | 状态定义、转移方程 |
| 回溯与贪心 | 排列组合、区间调度 | 剪枝、局部最优证明 |
这个分类不是固定的,你可以根据自己的刷题进度调整。关键是每个大类下面要有明确的子类,子类下面才是具体的题目。
3.2 第二步:为每道题建立结构化笔记
分类建好之后,每道题都要有一份结构化笔记。我用的模板是这样的:
题目编号: 题目名称: 难度: 所属子类: 核心思路:(一句话概括) 关键步骤: 1. 2. 3. 边界条件: 时间复杂度: 空间复杂度: 易错点: 同类题对比:这个模板看起来简单,但坚持填下来,你会发现自己的思路越来越清晰。尤其是“同类题对比”这一栏,逼着你去横向联系,效果非常好。
3.3 第三步:提炼专题通用模板
当一个专题积累了足够多的题目之后,就要开始提炼通用模板。比如二分查找,我汇总了十几道题之后,提炼出了三个模板:
- 标准二分:用于在有序数组中查找目标值。
- 左边界二分:用于查找第一个满足条件的元素。
- 右边界二分:用于查找最后一个满足条件的元素。
每个模板我都写清楚了适用场景、循环条件、边界更新方式。这样下次遇到新题,先判断属于哪种情况,直接套模板,正确率大幅提升。
注意:模板不是死记硬背的,一定要理解为什么循环条件是
left <= right还是left < right,为什么边界更新是right = mid还是right = mid - 1。不理解原理,模板用错了反而更危险。
3.4 第四步:定期回顾与更新
汇总不是一次性的工作。我每个月会花半天时间,把之前做的汇总翻一遍,看看有没有新的理解,有没有可以合并的模板,有没有之前归类错误的题目。这个过程本身就是一种复习,比重新做一遍题效率高得多。
4. 核心专题的汇总要点拆解
4.1 双指针与滑动窗口
双指针和滑动窗口是我最早做汇总的专题之一。这个专题的核心就一句话:用两个指针维护一个区间,通过移动指针来缩小搜索空间。
但具体到题目里,变化就多了。我汇总的时候重点区分了以下几种情况:
- 同向双指针:快慢指针,用于链表找环、数组去重。
- 相向双指针:左右指针,用于两数之和、反转数组。
- 滑动窗口:左右指针维护一个可变窗口,用于子串、子数组问题。
滑动窗口的模板我整理成了这样:
left = 0 for right in range(len(nums)): # 扩大窗口,加入 nums[right] while 窗口需要收缩: # 缩小窗口,移除 nums[left] left += 1 # 更新答案这个模板的关键在于什么时候收缩窗口。有的题是窗口内出现重复元素时收缩,有的是窗口内和超过目标值时收缩,有的是窗口大小固定时收缩。汇总的时候我把每种收缩条件都列了出来,对应到具体题目。
实操心得:滑动窗口的题目,最容易出错的地方是窗口收缩的时机和答案更新的位置。我建议在写代码之前,先用纸笔画一下窗口扩缩的过程,确认逻辑无误再动手。
4.2 动态规划的状态定义
动态规划是刷题路上的一座大山。我汇总DP专题的时候,发现最大的难点不是写转移方程,而是定义状态。状态定义对了,转移方程自然就出来了;状态定义错了,怎么推都推不出来。
我汇总DP题目的方法是:每道题都问自己三个问题。
- 这个问题的子问题是什么?
- 子问题的解用什么变量来表示?
- 当前状态和子状态之间是什么关系?
比如“最长递增子序列”这道题,子问题是“以第 i 个元素结尾的最长递增子序列长度”,状态就是dp[i],转移关系就是dp[i] = max(dp[j]) + 1,其中j < i且nums[j] < nums[i]。
我把这个思考过程记录在笔记里,下次遇到新的DP题,先套这三个问题,往往能快速找到切入点。
4.3 回溯的剪枝技巧
回溯法的框架很简单,就是“选择-递归-撤销选择”。但真正拉开差距的是剪枝。我汇总回溯专题的时候,专门整理了一份剪枝清单:
- 排序后剪枝:如果数组有序,可以提前终止循环。
- 去重剪枝:同一层不能选重复元素,用
used数组或索引控制。 - 可行性剪枝:当前路径已经不可能满足条件时,直接返回。
- 最优性剪枝:当前路径已经不可能优于已知最优解时,直接返回。
这份清单让我在做组合总和、全排列、子集这些问题时,能快速判断该用哪种剪枝策略。
4.4 二叉树的遍历与递归
二叉树的题目看起来多,但核心就两种:遍历和递归。我汇总的时候,把二叉树的题目分成了三类:
- 遍历类:前序、中序、后序、层序,包括递归和迭代两种写法。
- 属性类:求深度、求直径、判断平衡、判断对称。
- 构造类:从前序和中序构造、从后序和中序构造。
遍历类的题目,我要求自己递归和迭代都能手写。属性类的题目,我总结了一个通用思路:把问题分解为左右子树的问题,然后合并结果。构造类的题目,关键是找到根节点在中序数组中的位置,然后递归构造左右子树。
5. 汇总过程中的常见问题与排查
5.1 汇总变成抄题怎么办
这是最常见的问题。很多人做汇总,就是把题目和答案抄一遍,抄完就忘了。我的解决办法是:用自己的话重新表述。每道题的笔记,我都要求自己用一句话说清楚核心思路,不能用题目原文里的词。如果说不清楚,说明还没真正理解。
5.2 分类太细或太粗怎么办
分类太细,会导致每个子类下面只有一两道题,汇总的意义不大;分类太粗,又会导致一个子类下面几十道题,找不到规律。我的经验是:每个子类下面至少有五道题,最多不超过二十道。如果超过二十道,就说明需要进一步细分;如果少于五道,就先合并到相近的子类里。
5.3 汇总之后还是记不住怎么办
记不住是因为没有主动回忆。我自己的做法是:汇总完之后,合上笔记,拿一张白纸,把专题的核心模板默写一遍。默写不出来的地方,就是还没掌握的地方,回去重新看。这个过程很痛苦,但效果比反复看笔记好得多。
5.4 常见问题速查表
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 汇总变成抄题 | 没有用自己的话表述 | 每道题用一句话概括核心思路 |
| 分类太细 | 子类划分过多 | 合并相近子类,保证每个子类至少五道题 |
| 分类太粗 | 子类划分过少 | 按解题模式进一步细分 |
| 汇总后记不住 | 缺少主动回忆 | 合上笔记默写模板 |
| 汇总效率低 | 攒太多题才汇总 | 每十道题做一次小汇总 |
| 模板套用出错 | 不理解模板原理 | 先理解循环条件和边界更新逻辑 |
提示:汇总的质量比数量重要。我见过有人做了非常漂亮的汇总笔记,但都是抄的,自己根本没消化。这种汇总不如不做。
6. 让汇总真正产生效果的几个关键习惯
6.1 每道题都记录“卡点”
我做题的时候,遇到卡住的地方,会立刻在笔记里记下来:卡在哪一步、当时是怎么想的、后来是怎么想通的。这个“卡点记录”比题目答案本身更有价值,因为它反映的是思维盲区。下次遇到类似情况,翻一下卡点记录,往往能快速绕过。
6.2 定期做“无提示重做”
汇总做完之后,隔一周,把题目拿出来重新做一遍,但不看笔记。如果能在没有提示的情况下顺利做出来,说明真正掌握了;如果还是卡壳,说明汇总里的理解还不够深,需要重新整理。
6.3 用“教别人”的方式检验汇总质量
我有个习惯,每做完一个专题的汇总,就找一个也在刷题的朋友,给他讲一遍这个专题的核心思路。讲的过程中,如果对方能听懂并提出有价值的问题,说明我的汇总做到位了;如果我自己讲着讲着就乱了,说明汇总还有漏洞。
6.4 把汇总和面试表达结合起来
面试的时候,面试官不会让你默写代码,而是让你讲思路。所以我在做汇总的时候,会有意识地训练自己的表达能力。每道题的笔记里,我都会写一段“面试口述版”的思路,控制在两三句话以内,突出核心逻辑和关键决策点。
7. 汇总之后的下一步
汇总做完之后,不是就结束了。我通常会做两件事。
第一件是找同类新题验证。去题库里搜同一子类的题目,挑几道没做过的,限时做一遍。如果能快速AC,说明汇总有效;如果还是卡,说明汇总里遗漏了某些变体。
第二件是跨专题串联。比如把“滑动窗口”和“哈希表”放在一起看,把“动态规划”和“贪心”放在一起对比。很多难题之所以难,就是因为综合了多个专题的知识点。汇总的时候提前建立这种联系,遇到综合题就不会慌。
我个人在实际操作中的体会是,汇总这件事,前期投入的时间确实不少,但后期回报非常大。我刷到第三百道题的时候,明显感觉到自己看题的速度和准度都上了一个台阶,这跟坚持做汇总有直接关系。如果你现在刷题遇到了瓶颈,不妨停下来,把手头的题目好好汇总一遍,可能会有意想不到的收获。