1. 为什么我们需要LeetCode刷题笔记?
作为一名在互联网行业摸爬滚打多年的工程师,我见过太多人(包括当年的我自己)在准备技术面试时陷入"刷题焦虑"。LeetCode题库如今已经超过2000道题目,新手常常会问:"我该从哪开始?""为什么我的解法总是超时?""为什么同样的思路别人能写出更简洁的代码?"
这就是刷题笔记的价值所在——它不仅是解题过程的记录,更是思维方式的沉淀。好的笔记应该包含:
- 题目核心考察点的快速定位
- 多种解法的对比分析
- 代码实现中的易错点
- 时间/空间复杂度的计算过程
- 同类题目的举一反三
注意:千万不要把刷题笔记变成单纯的代码仓库。我曾面试过一位候选人,他能默写数十道题目的代码,但当被问到"为什么选择这种数据结构"时却哑口无言。
2. 如何构建有效的刷题笔记系统?
2.1 题目分类体系
根据我的实战经验,建议按照以下维度分类(以LeetCode为例):
| 分类维度 | 具体类型 | 代表题目 |
|---|---|---|
| 算法类型 | 动态规划/DFS/BFS/贪心等 | #70爬楼梯/#200岛屿数量 |
| 数据结构 | 链表/树/图/堆等 | #206反转链表/#215数组第K大 |
| 企业高频考点 | 各公司常考题 | #146LRU缓存/#297二叉树序列化 |
| 个人薄弱环节 | 根据错题统计 | 自定义分类 |
我习惯使用Notion搭建知识库,每个题目建立独立页面,模板包含:
markdown复制## 核心考点
## 初始思路
## 优化过程
## 最终解法
## 复杂度分析
## 相似题目
2.2 解题记录的黄金结构
一个完整的解题笔记应该包含这些要素:
-
问题重述(用自己的话描述)
- 避免直接复制题目描述
- 明确输入输出格式要求
- 标注特殊边界条件(如空输入、极大值等)
-
暴力解法(即使超时也要写)
- 记录第一直觉的解法
- 分析其时间复杂度瓶颈
- 例如两数之和的O(n²)枚举法
-
优化思路(最关键部分)
- 触发优化的关键观察点
- 数据结构选择依据
- 算法改进的推导过程
- 图示辅助说明(如双指针移动)
-
代码实现(带详细注释)
- 变量命名的语义化
- 关键步骤的注释说明
- 语言特性的合理运用
-
测试用例(覆盖各类场景)
- 常规情况
- 边界条件
- 极端案例
3. 高频题型深度解析
3.1 动态规划解题框架
以经典的#70爬楼梯问题为例,展示我的笔记方法:
问题转化:
- 将n阶楼梯转化为斐波那契数列问题
- 发现dp[i] = dp[i-1] + dp[i-2]的递推关系
代码演进:
python复制# 版本1:基础递归(O(2^n))
def climbStairs(n):
if n <= 2: return n
return climbStairs(n-1) + climbStairs(n-2)
# 版本2:记忆化搜索(O(n)空间)
memo = {}
def climbStairs(n):
if n in memo: return memo[n]
if n <= 2: return n
memo[n] = climbStairs(n-1) + climbStairs(n-2)
return memo[n]
# 版本3:动态规划(O(1)空间)
def climbStairs(n):
if n <= 2: return n
a, b = 1, 2
for _ in range(3, n+1):
a, b = b, a+b
return b
复杂度分析:
- 空间优化技巧:只需要维护前两个状态
- 可以扩展到步数变化的情况(如每次能走1/2/3步)
3.2 链表类题目技巧
以#206反转链表为例,分享几个易错点:
- 指针丢失问题:
python复制# 错误写法
curr = head
while curr:
next = curr.next
curr.next = prev # 此时原链表断裂
prev = curr
curr = next
# 正确写法应该先保存next指针
- 递归解法:
python复制def reverseList(head):
if not head or not head.next:
return head
new_head = reverseList(head.next)
head.next.next = head # 关键步骤
head.next = None
return new_head
- 调试技巧:
- 打印链表时添加箭头符号:1->2->3
- 可视化工具:draw.io绘制指针变化图
4. 高效刷题的工作流设计
4.1 每日刷题节奏
我推荐的训练计划(8周冲刺版):
| 时间段 | 任务类型 | 具体内容 |
|---|---|---|
| 早晨30分钟 | 复习昨日错题 | 重写代码+复杂度分析 |
| 午间1小时 | 新题练习 | 按分类选择2道中等难度 |
| 晚间2小时 | 深度总结 | 整理笔记+寻找相似题目 |
| 周末半天 | 模拟面试 | 随机抽题+白板编程 |
4.2 工具链配置
我的开发环境设置:
-
IDE插件:
- LeetCode Editor(VS Code)
- Code Runner(快速测试)
- Rainbow Brackets(代码可视化)
-
调试技巧:
python复制# 在代码中添加调试桩 def solve(nums): print(f"Input: {nums}") # 打印输入 # ...解题逻辑... print(f"Interim: {var}") # 关键变量监控 return result -
性能测试:
python复制import timeit setup = "from __main__ import solution" stmt = "solution(100000)" print(timeit.timeit(stmt, setup, number=10))
4.3 错题管理系统
我使用的错题标签体系:
- 🟥 思路错误(完全跑偏)
- 🟨 实现错误(思路正确但代码有bug)
- 🟦 优化不足(AC但性能差)
- 🟪 边界遗漏(未通过某些测试用例)
每周对错题进行统计分析,找出薄弱环节针对性突破。例如发现动态规划错误率较高时,可以:
- 重做《算法导论》相关章节
- 专项练习LIS、LCS等经典问题
- 整理状态转移方程模板
5. 从刷题到面试的实战转化
5.1 代码沟通技巧
面试时要注意:
-
明确问题:
- "输入规模大概是多少?"
- "是否需要处理负数情况?"
- "时间/空间复杂度有没有特别要求?"
-
思路演进:
- "我的第一想法是暴力解法,时间复杂度O(n²)..."
- "观察到数据有序性后,可以优化为二分查找..."
- "进一步考虑空间优化,可以用双指针..."
-
测试验证:
- "先用[1,2,3]这个常规案例测试..."
- "再考虑空数组的边界情况..."
- "最后验证超大输入时的表现..."
5.2 白板编程训练
我在家练习的方法:
- 使用60cm×90cm的白板
- 设置20分钟计时器
- 随机选择一道陌生题目
- 全程自言自语解释思路
- 录制视频回看改进点
常见问题诊断:
- 变量命名不清晰 → 提前设计命名规范
- 缩进混乱 → 练习整齐书写
- 忘记边界检查 → 建立检查清单
5.3 行为问题结合
当面试官问"你遇到过最有挑战的算法问题"时,可以:
- 选择笔记中记录深入的题目
- 展示当时的思考过程:
- "最初尝试了DFS但栈溢出..."
- "通过画图发现可以转化为拓扑排序..."
- "最终采用Kahn算法实现O(V+E)解法"
- 强调学到的经验:
- "现在遇到图问题会先分析性质..."
- "养成了先写测试用例的习惯..."
6. 进阶资源与持续提升
6.1 经典题库推荐
除LeetCode外,值得精刷的题库:
| 平台 | 特点 | 推荐题目 |
|---|---|---|
| Codeforces | 思维难度高 | Div2 C/D题 |
| AtCoder | 数学性强 | ABC Contest |
| 剑指Offer | 国内面试经典 | 全部题目 |
| Project Euler | 数学编程结合 | 前100题 |
6.2 源码学习建议
提升算法实现能力的秘诀:
-
研究Python内置库:
- collections模块的Counter实现
- heapq的堆排序算法
- bisect的二分查找实现
-
学习经典开源项目:
- Redis的跳表实现
- Numpy的矩阵运算优化
- Pandas的groupby机制
-
计算机系统基础:
- 缓存友好的算法设计
- 内存对齐的影响
- SIMD指令优化
6.3 算法竞赛入门路径
对于想深入算法领域的同学,我的建议路线:
-
第一阶段(1-3个月):
- 《算法图解》入门
- LeetCode热题100
- 每周参加LeetCode周赛
-
第二阶段(3-6个月):
- 《算法导论》精读
- Codeforces达到蓝名
- 实现经典算法轮子
-
第三阶段(6个月+):
- 专题突破(数论/计算几何等)
- 组队参加ICPC/Google Code Jam
- 研究论文级算法
最后分享一个真实体会:去年我用这套方法辅导一位转专业的学生,他从最初连Two Sum都写不利索,到6个月后拿到FAANG offer。关键不在于刷题数量,而在于这种深度笔记带来的思维蜕变。现在他依然保持着每个题目至少写300字分析的习惯,这比单纯追求解题数量重要得多。
