1. 刷题方法论概述
最近两周(3.9-3.14)集中刷题的实战经历让我对算法训练有了新的认识。这段时间我主要聚焦在LeetCode中等难度题目,覆盖了动态规划、二叉树和链表三大高频考点。不同于碎片化刷题,这种集中训练能快速建立解题直觉,特别适合准备技术面试或竞赛的同学。
重要提示:连续刷题期间建议保持每天3-5题的节奏,太少难以形成肌肉记忆,太多容易导致疲劳积累。
我采用的刷题策略是"分类突破+错题重做":先用2天时间专攻某一类题型,建立解题模板;随后用1天重做之前的错题。实测发现,这种方法比随机刷题效率提升约40%,尤其对动态规划这类需要模式识别的题型效果显著。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心题型解析与实战记录
2.1 动态规划专题突破
本周重点攻克了背包问题和序列DP。以经典的"322. 零钱兑换"为例,解题时需要明确三个关键点:
- 状态定义:dp[i]表示组成金额i所需的最少硬币数
- 转移方程:dp[i] = min(dp[i], dp[i-coin]+1)
- 初始化:dp[0]=0,其他位置初始化为INF
实际编码时容易踩的坑:
python复制# 错误示范:未处理无法兑换的情况
def coinChange(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount+1):
dp[i] = min(dp[i], dp[i-coin]+1)
return dp[amount] # 当无法兑换时仍返回INF
# 正确解法
return dp[amount] if dp[amount] != float('inf') else -1
2.2 二叉树遍历技巧
二叉树的非递归遍历常作为面试白板题出现。以下是前序遍历的迭代实现要点:
python复制def preorderTraversal(root):
res = []
stack = [root]
while stack:
node = stack.pop()
if node:
res.append(node.val)
stack.append(node.right) # 先右后左
stack.append(node.left)
return res
实测发现,用栈模拟递归时,90%的错误源于压栈顺序错误。记住口诀:"前序中序改压栈,后序反转最特别"。
2.3 链表操作陷阱
链表题的bug通常出现在边界条件处理。比如"25. K个一组翻转链表",需要特别注意:
- 剩余节点不足k个时不翻转
- 每组翻转后要正确连接前后组
- 虚拟头节点能简化首组处理
python复制def reverseKGroup(head, k):
dummy = ListNode(0, head)
pre = dummy
while True:
# 检查剩余节点是否够k个
last = pre
for _ in range(k):
last = last.next
if not last:
return dummy.next
# 翻转当前组
curr = pre.next
for _ in range(k-1):
next_node = curr.next
curr.next = next_node.next
next_node.next = pre.next
pre.next = next_node
pre = curr
3. 效率提升工具链配置
3.1 本地调试环境搭建
推荐使用VS Code配合以下插件:
- LeetCode插件:直接提交测试
- Code Runner:快速执行单文件
- Python Test Explorer:管理测试用例
我的调试模板:
python复制import unittest
class Test(unittest.TestCase):
def test_case1(self):
self.assertEqual(Solution().func(param), expected)
if __name__ == "__main__":
unittest.main()
3.2 刷题进度追踪表
| 日期 | 题型 | 题号 | 完成状态 | 重做次数 |
|---|---|---|---|---|
| 3.9 | 动态规划 | 322, 518, 416 | ✅ | 2 |
| 3.10 | 二叉树 | 94, 144, 145 | ✅ | 1 |
| 3.11 | 链表 | 25, 138, 146 | ✅ | 3 |
| 3.12 | 错题重做 | 322, 25, 416 | ✅ | - |
| 3.13 | 动态规划 | 72, 115, 139 | ✅ | 1 |
| 3.14 | 综合练习 | 215, 347, 238 | ✅ | - |
4. 高频错题分析与改进方案
4.1 动态规划状态定义错误
在"72. 编辑距离"中,初期错误地将状态定义为dp[i][j]表示word1前i个和word2前j个的匹配情况,导致状态转移混乱。正确做法:
- dp[i][j]:word1前i个转word2前j个的最小操作数
- 初始化:dp[i][0]=i (全删除), dp[0][j]=j (全插入)
- 转移方程:
python复制if word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1] else: dp[i][j] = 1 + min( dp[i-1][j], # 删除 dp[i][j-1], # 插入 dp[i-1][j-1] # 替换 )
4.2 二叉树指针丢失问题
"114. 二叉树展开为链表"要求原地修改,常见错误是直接前序遍历存储节点再重建,不符合空间要求。正确解法是先展开左右子树,再将左子树插入根与右子树之间:
python复制def flatten(root):
while root:
if root.left:
pre = root.left
while pre.right:
pre = pre.right
pre.right = root.right
root.right = root.left
root.left = None
root = root.right
4.3 链表虚拟头节点遗漏
"138. 复制带随机指针的链表"需要处理随机指针的映射关系。最优解法是三次遍历:
- 在原节点后插入复制节点
- 设置random指针:cur.next.random = cur.random.next
- 分离两个链表
python复制def copyRandomList(head):
if not head: return None
# 第一步:插入新节点
cur = head
while cur:
new = Node(cur.val, cur.next)
cur.next = new
cur = new.next
# 第二步:设置random
cur = head
while cur:
if cur.random:
cur.next.random = cur.random.next
cur = cur.next.next
# 第三步:分离链表
new_head = head.next
cur = head
while cur:
temp = cur.next
cur.next = temp.next
if temp.next:
temp.next = temp.next.next
cur = cur.next
return new_head
5. 时间管理与复盘策略
5.1 每日刷题节奏安排
推荐的时间分配方案:
- 上午(1.5小时):新题攻克
- 15分钟:读题+思路构建
- 30分钟:编码实现
- 15分钟:测试调试
- 30分钟:看最优解+重构代码
- 下午(1小时):错题重做
- 晚上(0.5小时):整理笔记
5.2 错题本记录规范
有效的错题记录应包含:
- 原始错误代码片段
- 错误类型(边界条件/逻辑错误/优化不足)
- 正确解法思路图示
- 同类题变式(如背包问题中的完全背包vs 01背包)
示例记录格式:
code复制【题目】322. 零钱兑换
【错误】未处理amount=0的情况
【原因】初始化时遗漏dp[0]=0
【改进】增加边界条件检查
【变式】518. 零钱兑换II(求组合数)
6. 进阶训练建议
当常规题目正确率稳定在80%以上时,可以尝试:
- 限制解题时间(中等题20分钟)
- 用不同语言实现(如Python转Java)
- 尝试一题多解(如递归改迭代)
- 参加周赛锻炼临场发挥
对于想冲击ACM级别的选手,建议:
- 每天增加1道hard题
- 学习高级数据结构(线段树、Trie等)
- 研究论文级优化方案(如KMP算法的改进)
