LeetCode Hot 100 快速入门报告¶
视角:多年未刷算法的工程师 目标:两到四周内把手感找回来,能从容应对面试中 80% 的中等题 语言:Python(语法干净,省下的时间留给思考)
0. 写在前面:这份报告是什么¶
如果你曾经会写树的递归、会推 DP 转移方程,但工作几年后看到 dfs(node.left) 都要愣两秒——这份报告就是给你的。
它不是题解集,也不打算让你刷完 100 道。它做三件事:
- 帮你重建套路地图:知道哪类问题对应哪种解法,而不是每题都从零想。
- 给你一份40 题的最小可行集:刷完这 40 道,剩下 60 道大多是变种。
- 提供逐类模板代码:背下来不是耻辱,是效率。面试官想看你解决问题,不是发明轮子。
读完本报告需要 30 分钟,配套刷题约 40-80 小时(4 周 × 每天 1.5-3 小时)。
1. 你失去的 vs 你还剩的¶
久疏战阵的人最容易犯两个错:高估自己("我以前会的,看一眼就行")或低估自己("完全不会了,得从头学")。事实是:
| 你失去的 | 你还剩的 |
|---|---|
| 边界条件的肌肉记忆(off-by-one、空指针) | 工程能力(命名、调试、拆解问题) |
| 各种模板代码的瞬时回忆 | 对复杂度的直觉判断 |
| 对题型的快速识别 | 对系统/数据结构的深刻理解 |
| 在白板上无 IDE 写对代码 | 阅读和理解长代码的能力 |
结论:你的瓶颈不是"理解力",而是模式识别 + 模板熟练度。所以策略不是"从《算法导论》重读",而是按套路分类,每类刷透 3-5 道,建立条件反射。
2. 30 天重启路线图¶
按"先简单结构,后复杂算法;先模板题,后变种题"的顺序,避免一上来就被 DP 劝退。
| 周次 | 主题 | 重点套路 | 题量 | 心态 |
|---|---|---|---|---|
| W1 | 手感恢复 | 哈希、双指针、滑动窗口、栈 | 10-12 | 把语法和 IDE 找回来 |
| W2 | 结构题 | 链表、二叉树、图论基础 | 10-12 | 递归和指针的肌肉记忆 |
| W3 | 搜索类 | 二分、回溯、堆、贪心 | 8-10 | 学会"分类后选模板" |
| W4 | 动态规划 | 一维 DP、背包、多维 DP | 8-10 | 不慌,DP 也是套路 |
每天的节奏(90 分钟版本):
- 10 min:复习昨天的题,能在白纸上默写模板就过
- 60 min:做 1-2 道新题(中等题为主),先想 15 分钟,想不出来直接看题解
- 20 min:把题解的关键思路用自己的话写在笔记里(不要抄代码)
关键纪律:
- ❌ 不要按 LeetCode 题号顺序刷
- ❌ 不要"想 1 小时还没思路"硬扛——看题解不丢人,复盘才是关键
- ✅ 同一类题连续刷 3-5 道,强化模式识别
- ✅ 第二天默写昨天的模板,第七天再默写一次
3. 算法套路地图¶
一张表看完 Hot 100 的全部套路。看到题先在脑子里过一遍这张表,匹配到哪类就用哪个模板。
| 套路 | 触发信号(题目长这样就用它) | 核心数据结构 | Hot 100 占比 |
|---|---|---|---|
| 哈希 | "两个数和为 X"、"找重复/计数" | dict / set | ~5% |
| 双指针 | 有序数组找配对、原地操作 | 两个指针 | ~5% |
| 滑动窗口 | "连续子数组/子串"满足某条件 | 双指针 + 计数器 | ~5% |
| 前缀和 | 区间和、子数组和为 K | 数组 + 哈希 | ~3% |
| 链表 | 题目给 ListNode | 指针 + 虚拟头节点 | ~14% |
| 二叉树 | 题目给 TreeNode | 递归 / BFS 队列 | ~15% |
| 图/网格 | 二维矩阵 BFS/DFS、拓扑 | 队列 + visited | ~4% |
| 回溯 | "所有方案/排列/组合" | 递归 + 状态恢复 | ~8% |
| 二分 | 有序数组找位置、"最小的最大" | 左右指针 | ~6% |
| 栈 | 括号匹配、"下一个更大元素" | stack / 单调栈 | ~5% |
| 堆 | "Top K"、动态中位数 | heapq | ~3% |
| 贪心 | "最少次数/最远距离" | 一次遍历 | ~4% |
| DP | "最值/方案数"且无法贪心 | 一维/二维数组 | ~15% |
| 技巧题 | 位运算、摩尔投票、原地哈希 | 看具体题 | ~8% |
记忆口诀:
- 配对找数 → 哈希
- 有序/原地 → 双指针
- 连续子串 → 滑动窗口
- 区间和 → 前缀和
- 所有方案 → 回溯
- Top K → 堆
- 最值方案数 → DP
4. 十五大套路逐个击破¶
每类的结构:直觉 → 模板 → 必刷题 → 易错点。
4.1 哈希表¶
直觉:用空间换时间,把"O(n) 查找"变成"O(1) 查找"。看到"找一个数"先想"能不能预先记下来"。
模板:
# 两数之和(典型套路)
def twoSum(nums, target):
seen = {} # value -> index
for i, x in enumerate(nums):
if target - x in seen:
return [seen[target - x], i]
seen[x] = i
必刷题(3 道):
- 1. 两数之和 — 模板题
- 49. 字母异位词分组 — key 用 sorted(s) 或 26 字母计数元组
- 128. 最长连续序列 — 关键:只从"序列起点"开始数(
x-1 not in set)
易错点:
dict的 value 存 index 还是 count?想清楚再写- 第 128 题不优化的写法是 O(n²),必须只从起点开始
4.2 双指针¶
直觉:在有序或原地修改的数组上,两个指针往中间走(对撞)或同方向走(快慢)。
模板:
# 对撞指针:三数之和
def threeSum(nums):
nums.sort()
res = []
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i-1]: continue # 去重
l, r = i + 1, len(nums) - 1
while l < r:
s = nums[i] + nums[l] + nums[r]
if s == 0:
res.append([nums[i], nums[l], nums[r]])
while l < r and nums[l] == nums[l+1]: l += 1
while l < r and nums[r] == nums[r-1]: r -= 1
l += 1; r -= 1
elif s < 0: l += 1
else: r -= 1
return res
必刷题(4 道):
- 283. 移动零 — 快慢指针入门
- 11. 盛最多水的容器 — 对撞指针,关键证明"短板移动"
- 15. 三数之和 — 排序 + 双指针,面试高频
- 42. 接雨水 — 对撞指针 / 单调栈 两种解法都要会
易错点:
- 三数之和的去重:
i > 0 and nums[i] == nums[i-1]是 i 的去重,循环内是 l/r 的去重 - 接雨水推荐先用双指针(O(1) 空间),单调栈作为加分项
4.3 滑动窗口¶
直觉:双指针的变种。窗口 = [l, r],r 一直右移扩张,条件被打破时 l 才右移收缩。
模板(背下来):
def slidingWindow(s):
cnt = {}
l = 0
ans = 0
for r in range(len(s)):
# 1. 把 s[r] 加入窗口
cnt[s[r]] = cnt.get(s[r], 0) + 1
# 2. 窗口不满足条件就收缩 l
while window_invalid():
cnt[s[l]] -= 1
if cnt[s[l]] == 0: del cnt[s[l]]
l += 1
# 3. 更新答案
ans = max(ans, r - l + 1)
return ans
必刷题(3 道):
- 3. 无重复字符的最长子串 — 模板题
- 438. 找到字符串中所有字母异位词 — 定长窗口
- 76. 最小覆盖子串 — 变长窗口,难度上一档,面试高频
易错点:
- 窗口长度公式:
r - l + 1 - "定长窗口" vs "变长窗口" 是两种写法,76 题是后者
- 记得在
cnt[c] == 0时把 key 删掉,否则比较哈希字典会出错
4.4 前缀和¶
直觉:区间和 = 前缀和之差。处理"子数组和"时几乎必用。
模板:
# 和为 K 的子数组
def subarraySum(nums, k):
pre_count = {0: 1} # 前缀和 -> 出现次数
pre_sum = 0
ans = 0
for x in nums:
pre_sum += x
# 如果存在某个前缀和 = pre_sum - k,就有对应的子数组
ans += pre_count.get(pre_sum - k, 0)
pre_count[pre_sum] = pre_count.get(pre_sum, 0) + 1
return ans
必刷题(2 道):
- 560. 和为 K 的子数组 — 前缀和 + 哈希经典组合
- 238. 除自身以外数组的乘积 — 前缀积 + 后缀积思想
易错点:
pre_count[0] = 1这一句别忘了,处理"从下标 0 开始"的情况- 不要先把所有前缀和算好再查询,边算边查才是 O(n)
4.5 链表¶
直觉:链表题 90% 用三个技巧:虚拟头节点(dummy)、快慢指针、画图。先画图再写代码。
模板 - 反转链表(必背):
def reverseList(head):
prev, cur = None, head
while cur:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
return prev
模板 - 快慢指针找环:
def hasCycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast: return True
return False
必刷题(8 道,按难度排序):
- 206. 反转链表 — 模板题,必须默写
- 21. 合并两个有序链表 — 递归 / 迭代两种写法
- 141. 环形链表 — 快慢指针入门
- 142. 环形链表 II — 快慢指针 + 数学(Floyd 判圈)
- 160. 相交链表 — 双指针走两遍
- 19. 删除倒数第 N 个节点 — 快慢指针 + dummy
- 25. K 个一组翻转链表 — 反转模板的进阶应用
- 146. LRU 缓存 — 双向链表 + 哈希,面试超高频
易错点:
- 任何"可能删除头节点"的题,先建
dummy = ListNode(0, head),最后返回dummy.next - 反转链表前一定要先保存
next,否则丢链 - LRU 自己实现双向链表节点比用 OrderedDict 更能展示功力
4.6 二叉树¶
直觉:二叉树就是递归。问自己三件事:
- 递归函数返回什么?(深度?是否平衡?路径和?)
- 左右子树各自递归的结果怎么合并?
- base case 是什么?(一般是
if not root: return ...)
模板 - 通用递归:
def dfs(root):
if not root: return base_value
left = dfs(root.left)
right = dfs(root.right)
# 用 left, right, root.val 合并出当前层的答案
return combine(left, right, root.val)
模板 - 层序遍历(BFS):
from collections import deque
def levelOrder(root):
if not root: return []
q = deque([root])
res = []
while q:
level = []
for _ in range(len(q)): # 关键:固定本层节点数
node = q.popleft()
level.append(node.val)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
res.append(level)
return res
必刷题(10 道):
- 94. 中序遍历 — 递归 + 迭代(栈)两种写法
- 104. 最大深度 — 最简单的递归入门
- 226. 翻转二叉树 — Homebrew 作者翻车题,必会
- 101. 对称二叉树 — 双指针式递归
- 102. 层序遍历 — BFS 模板
- 199. 二叉树右视图 — BFS 取每层最后一个
- 543. 二叉树直径 — "返回深度,更新全局答案"模式
- 98. 验证 BST — 用上下界递归,不要只比较父子
- 236. 最近公共祖先 — 经典递归思维题
- 124. 二叉树最大路径和 — 直径题的高阶版,面试高频
进阶(可选):
- 105. 从前序与中序构造二叉树 — 分治
- 437. 路径总和 III — 前缀和在树上的应用
- 114. 展开为链表 — 递归 + 反向中序
易错点:
- 验证 BST 不能只
root.left.val < root.val < root.right.val,必须传上下界 - 直径题:递归函数返回深度,但用全局变量记录最大直径
- 层序遍历的
for _ in range(len(q))必须先取 len 再循环,否则会越界
4.7 图与网格¶
直觉:网格题(岛屿、腐烂橘子)= 在二维数组上 BFS/DFS。图论题(课程表)= 拓扑排序。
模板 - 网格 DFS:
def numIslands(grid):
if not grid: return 0
m, n = len(grid), len(grid[0])
def dfs(i, j):
if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] != '1':
return
grid[i][j] = '0' # 原地改 visited
for di, dj in [(-1,0),(1,0),(0,-1),(0,1)]:
dfs(i+di, j+dj)
count = 0
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
count += 1
dfs(i, j)
return count
模板 - 拓扑排序:
from collections import defaultdict, deque
def canFinish(numCourses, prerequisites):
graph = defaultdict(list)
indegree = [0] * numCourses
for a, b in prerequisites:
graph[b].append(a)
indegree[a] += 1
q = deque([i for i in range(numCourses) if indegree[i] == 0])
visited = 0
while q:
node = q.popleft()
visited += 1
for nxt in graph[node]:
indegree[nxt] -= 1
if indegree[nxt] == 0:
q.append(nxt)
return visited == numCourses
必刷题(4 道):
- 200. 岛屿数量 — DFS 模板题
- 994. 腐烂的橘子 — 多源 BFS
- 207. 课程表 — 拓扑排序模板题
- 208. 实现 Trie — 字典树数据结构
易错点:
- 网格题用"原地改"代替
visited数组省内存,但要确认题目允许修改 - 多源 BFS 是把所有起点先全部入队,不是只放一个
- 拓扑排序用 BFS(Kahn 算法)比 DFS 更不容易写错
4.8 回溯¶
直觉:枚举"所有方案"。三件套:选择 → 递归 → 撤销。
通用模板(必背):
def backtrack(path, choices):
if 满足结束条件:
res.append(path[:]) # 注意拷贝
return
for choice in choices:
if 不合法: continue
path.append(choice) # 选择
backtrack(path, new_choices) # 递归
path.pop() # 撤销
必刷题(6 道,难度递增):
- 78. 子集 — "选或不选"模板
- 46. 全排列 — 用 used 数组的模板
- 17. 电话号码字母组合 — 树形回溯入门
- 39. 组合总和 — 元素可重复用,用 start 控制顺序
- 22. 括号生成 — 用"剩余左右括号数"剪枝
- 79. 单词搜索 — 网格 + 回溯,要 visited
进阶:
- 131. 分割回文串 — 切片回溯
- 51. N 皇后 — 经典难题,加分项
易错点:
res.append(path[:])必须是拷贝,不然后续 path 修改会污染结果- 组合题用
start控制顺序避免重复,排列题用used[]标记 - 单词搜索的 visited 必须在递归后撤销
4.9 二分查找¶
直觉:只要存在"单调性"就能二分。不一定数组本身要有序,比如"在 [1, n] 中找最小的满足条件 X 的数"也可以二分。
模板(闭区间版本,背这个就够了):
def binarySearch(nums, target):
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
l = mid + 1
else:
r = mid - 1
return -1 # 或 l,看题目要返回插入位置时
必刷题(5 道):
- 35. 搜索插入位置 — 标准二分
- 34. 在排序数组中查找第一个和最后一个位置 — 左右边界二分
- 74. 搜索二维矩阵 — 把矩阵当一维数组
- 153. 寻找旋转排序数组中的最小值 — "旋转数组"思维
- 33. 搜索旋转排序数组 — 上一题的进阶
地狱难度(可跳过):
- 4. 寻找两个正序数组的中位数 — Hard,二分边界极绕,初学者不必硬攻
易错点:
- 死循环:
l <= r配mid + 1/mid - 1,这一组绝对不会死循环 - "找第一个 >= target"和"找最后一个 <= target"是两种写法,建议背一个模板(推荐用
bisect_left/bisect_right的实现思路)
4.10 栈与单调栈¶
直觉:
- 普通栈:括号匹配、撤销操作。
- 单调栈:找"下一个更大/更小的元素",几乎是固定套路。
模板 - 单调栈(找下一个更大元素):
def dailyTemperatures(T):
n = len(T)
res = [0] * n
stack = [] # 存下标,对应的温度是递减的
for i in range(n):
while stack and T[stack[-1]] < T[i]:
j = stack.pop()
res[j] = i - j
stack.append(i)
return res
必刷题(5 道):
- 20. 有效的括号 — 栈入门
- 155. 最小栈 — 辅助栈技巧
- 394. 字符串解码 — 双栈模拟
- 739. 每日温度 — 单调栈模板题
- 84. 柱状图中最大的矩形 — 单调栈 Hard,面试高频
易错点:
- 单调栈一般存下标而不是值,方便算距离
- 84 题的技巧:在数组前后加哨兵
[0],省去边界判断
4.11 堆¶
直觉:"Top K"问题、"动态求中位数"几乎必用堆。Python 的 heapq 是小顶堆,要大顶堆就存负数。
模板 - Top K(最大 K 个):
import heapq
def topK(nums, k):
# 维护一个大小为 k 的小顶堆
heap = []
for x in nums:
heapq.heappush(heap, x)
if len(heap) > k:
heapq.heappop(heap)
return heap # 堆里就是前 k 大
必刷题(3 道):
- 215. 数组中的第 K 个最大元素 — 堆 / 快速选择两种解法
- 347. 前 K 个高频元素 — 堆 + 哈希
- 295. 数据流的中位数 — 大顶堆 + 小顶堆,面试经典
易错点:
- 求前 K 大用小顶堆(淘汰小的),反之亦然——这点容易绕晕
- 295 题维护两个堆,大顶堆装较小的一半,差值不超过 1
4.12 贪心¶
直觉:每一步选当前最优,不回头。关键是要证明贪心策略正确——但面试时观察 + 直觉即可,证明是数学家的工作。
必刷题(4 道):
- 121. 买卖股票的最佳时机 — "维护最小值"贪心
- 55. 跳跃游戏 — 维护"能到达的最远位置"
- 45. 跳跃游戏 II — 上一题的进阶(最少跳几次)
- 763. 划分字母区间 — 预处理 + 贪心
易错点:
- 贪心和 DP 经常长得像,先想能不能贪心(更简单),不行再上 DP
- "跳跃游戏"系列的关键是维护一个边界
4.13 动态规划(一维)¶
直觉:DP 三件套——
- 定义状态:
dp[i]是什么? - 写转移方程:
dp[i]怎么从dp[i-1]、dp[i-2]推出? - 初始化和边界:
dp[0]是多少?
口诀:"最值/方案数 + 无后效性" 就用 DP。无后效性 = 当前状态只依赖过去,不依赖未来。
模板 - 打家劫舍:
def rob(nums):
if not nums: return 0
if len(nums) == 1: return nums[0]
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
return dp[-1]
必刷题(6 道,按难度递增):
- 70. 爬楼梯 — DP 入门(其实就是斐波那契)
- 198. 打家劫舍 — 经典一维 DP
- 53. 最大子数组和 — Kadane 算法(DP 的特例)
- 300. 最长递增子序列 — O(n²) DP + 二分优化到 O(n log n)
- 322. 零钱兑换 — 完全背包入门
- 139. 单词拆分 — 字符串 + DP
进阶:
- 152. 乘积最大子数组 — 同时维护 max 和 min(因为负数)
- 416. 分割等和子集 — 01 背包模板
- 279. 完全平方数 — 完全背包
易错点:
- 53 题的 DP 状态是"以 i 结尾的最大子数组和",不是"前 i 个的最大和"
- 322 题用
dp[i] = min(dp[i], dp[i-coin] + 1),初始化为inf - 大多数一维 DP 都能空间优化到 O(1)(用两三个变量代替数组)
4.14 动态规划(多维)¶
直觉:状态有两个维度(比如两个字符串、二维网格)。状态定义往往是 dp[i][j] = "前 i 个 X 和前 j 个 Y 的某指标"。
模板 - 最长公共子序列:
def longestCommonSubsequence(s1, s2):
m, n = len(s1), len(s2)
dp = [[0] * (n+1) for _ in range(m+1)]
for i in range(1, m+1):
for j in range(1, n+1):
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]
必刷题(5 道):
- 62. 不同路径 — 二维 DP 入门
- 64. 最小路径和 — 同上变种
- 5. 最长回文子串 — 中心扩展 / DP 两种解法
- 1143. 最长公共子序列 — 双串 DP 模板
- 72. 编辑距离 — 双串 DP 王者,面试超高频
易错点:
- 双串 DP 的下标对齐:
dp[i][j]通常对应s1[i-1]和s2[j-1](因为多了 0 行 0 列) - 编辑距离的三种操作(插入、删除、替换)对应
dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1],画图理解
4.15 技巧题¶
这一类不在主线套路里,但 Hot 100 占比不小,面试爱考因为"想到就过、想不到就跪"。
必刷题(5 道):
- 136. 只出现一次的数字 — 异或(
a ^ a = 0) - 169. 多数元素 — 摩尔投票
- 31. 下一个排列 — 找规律 + 双指针
- 75. 颜色分类 — 三指针(荷兰国旗)
- 287. 寻找重复数 — 快慢指针在数组上的应用(Floyd 判圈)
易错点:
- 这类题不必硬想,记住套路名字就好
- 异或的三条性质:
a^0=a、a^a=0、满足交换律——刷题一辈子能用十次
5. 精选 40 题刷题清单¶
优先级 P0(必刷,20 题):模板题 + 高频题。刷完这 20 题,面试 50% 中等题能稳过。
| # | 题目 | 套路 | 难度 |
|---|---|---|---|
| 1 | 两数之和 | 哈希 | Easy |
| 15 | 三数之和 | 双指针 | Medium |
| 3 | 无重复字符的最长子串 | 滑动窗口 | Medium |
| 560 | 和为 K 的子数组 | 前缀和 | Medium |
| 53 | 最大子数组和 | DP | Medium |
| 206 | 反转链表 | 链表 | Easy |
| 21 | 合并两个有序链表 | 链表 | Easy |
| 141 | 环形链表 | 快慢指针 | Easy |
| 146 | LRU 缓存 | 链表+哈希 | Medium |
| 104 | 二叉树最大深度 | 递归 | Easy |
| 102 | 二叉树层序遍历 | BFS | Medium |
| 236 | 最近公共祖先 | 递归 | Medium |
| 200 | 岛屿数量 | DFS | Medium |
| 46 | 全排列 | 回溯 | Medium |
| 78 | 子集 | 回溯 | Medium |
| 20 | 有效的括号 | 栈 | Easy |
| 215 | 第 K 大的元素 | 堆 | Medium |
| 121 | 买卖股票最佳时机 | 贪心 | Easy |
| 70 | 爬楼梯 | DP | Easy |
| 198 | 打家劫舍 | DP | Medium |
优先级 P1(强化训练,15 题):每类的进阶题。
| # | 题目 | 套路 | 难度 |
|---|---|---|---|
| 128 | 最长连续序列 | 哈希 | Medium |
| 11 | 盛最多水的容器 | 双指针 | Medium |
| 76 | 最小覆盖子串 | 滑动窗口 | Hard |
| 142 | 环形链表 II | 链表 | Medium |
| 25 | K 个一组翻转链表 | 链表 | Hard |
| 98 | 验证 BST | 递归 | Medium |
| 124 | 二叉树最大路径和 | 递归 | Hard |
| 199 | 二叉树右视图 | BFS | Medium |
| 207 | 课程表 | 拓扑排序 | Medium |
| 39 | 组合总和 | 回溯 | Medium |
| 22 | 括号生成 | 回溯 | Medium |
| 33 | 搜索旋转排序数组 | 二分 | Medium |
| 739 | 每日温度 | 单调栈 | Medium |
| 322 | 零钱兑换 | DP | Medium |
| 72 | 编辑距离 | DP | Hard |
优先级 P2(加分项,5 题):硬骨头,刷完显著拉开差距。
| # | 题目 | 套路 | 难度 |
|---|---|---|---|
| 42 | 接雨水 | 双指针/单调栈 | Hard |
| 84 | 柱状图最大矩形 | 单调栈 | Hard |
| 295 | 数据流的中位数 | 双堆 | Hard |
| 300 | 最长递增子序列 | DP + 二分 | Medium |
| 4 | 两个正序数组中位数 | 二分 | Hard |
刷完顺序建议:P0 全刷 → 回头复习 P0 默写 → P1 全刷 → P2 选做。
6. 复盘心法¶
刷题不是输入题量,是输出模式识别。下面六条是给"久疏战阵"的人最有效的:
- 看题先识别套路,再写代码。如果看完题没想到属于哪类,先看第 3 节那张表。
- 15 分钟想不出就看题解。看题解不是失败,第二天默写才是真复习。
- 每周日做"默写测试":白纸上默写本周学过的所有模板(5-7 个),写不出来的回去重做对应题。
- 同类题连刷,不要今天哈希明天 DP 后天链表,那是浪费时间。
- 每道题写一句话题解,写到自己的笔记里。一年后回头看一句话就能想起整道题。
- 拒绝完美主义:100 道题不必全刷,40 道刷透 > 80 道刷过。
7. 常见陷阱速查¶
| 陷阱 | 表现 | 对策 |
|---|---|---|
| 只看题解不动手 | "我看懂了" → 第二天忘光 | 强制白纸默写 |
| 刷题不分类 | 按题号顺序刷,毫无套路感 | 按本报告的 15 类刷 |
| 死磕一道题 2 小时 | 自我感动,效率极低 | 15 分钟为界,超时看题解 |
| 收藏夹吃灰 | 收藏 200 篇题解从不看 | 只收藏 5 类核心模板 |
| 追求一遍过 | 害怕看题解,刷得慢 | 第一遍允许看,第三遍要求独立 |
| 只刷 Easy | 信心爆棚但面试翻车 | 70% 时间花在 Medium |
| 跳过 DP | "我不擅长 DP" | DP 是最套路化的,反而最容易补 |
8. 4 周后你应该长什么样¶
- 看到"两数 / 配对" → 立刻想到哈希
- 看到"子数组连续" → 立刻想到滑动窗口或前缀和
- 看到
TreeNode→ 手指开始打字if not root: return - 看到"所有方案" → 立刻拿出回溯三件套
- 看到"最值且无后效性" → 开始定义
dp[i] - 拿到一道新中等题,5 分钟内能说出大致思路,30 分钟内能写完调通
做到这些,面试中等题命中率 70%+,Hot 100 也算是真正"刷完"了。
附录:本报告引用的所有题目¶
按出现顺序列出(共 60+ 道,覆盖 Hot 100 的核心 ~60%):
哈希: 1, 49, 128
双指针: 11, 15, 42, 283
滑窗: 3, 76, 438
前缀和: 238, 560
链表: 19, 21, 25, 141, 142, 146, 160, 206
二叉树: 94, 98, 101, 102, 104, 105, 114, 124, 199, 226, 236, 437, 543
图论: 200, 207, 208, 994
回溯: 17, 22, 39, 46, 51, 78, 79, 131
二分: 4, 33, 34, 35, 74, 153
栈: 20, 84, 155, 394, 739
堆: 215, 295, 347
贪心: 45, 55, 121, 763
DP: 5, 53, 62, 64, 70, 72, 139, 152, 198, 279, 300, 322, 416, 1143
技巧: 31, 75, 136, 169, 287
祝刷题愉快。多年未刷不是问题,找对方法 4 周就能回到状态。