算法题
数据结构与算法的实战手册,从模板到经典题,从暴力到最优。
刷题方法论
先按专题刷透 → 再混合复习 → 计时模拟面试
刷题不是盲目堆量,而是有策略地系统性提高。推荐三阶段法:
阶段 1:专题突破(约 200 题)
按数据结构或算法技巧分类,集中刷同一类型题目,形成肌肉记忆。例如先把所有双指针题目做完,再进入滑动窗口。
推荐顺序:
1. 数组与字符串(10-15 题)→ 熟悉基础
2. 链表(10 题)→ 掌握指针操作
3. 哈希表(10 题)→ O(1) 查找思维
4. 双指针(10 题)→ 对撞、快慢
5. 二分查找(10 题)→ 边界处理
6. 滑动窗口(10 题)→ 定长/不定长
7. 栈与队列(10 题)→ 单调栈引入
8. 树(15 题)→ 递归思维
9. 回溯(15 题)→ 组合/排列/子集
10. 动态规划(30 题)→ 五步法
11. 图论(15 题)→ BFS/DFS/拓扑
12. 贪心(10 题)→ 区间调度阶段 2:混合复习(约 100 题)
打乱顺序做题,锻炼识别题型能力——看到题目能在 30 秒内判断属于哪类算法。
阶段 3:计时模拟(每周 2-3 次)
模拟真实面试场景:
- 45 分钟内完成一道中等难度题(包括沟通、编码、测试全流程)。
- 录屏回放,分析自己的表达和思路。
- 找朋友/前同事做 mock interview。
知识地图
必备数据结构(按重要性排序)
| 模块 | 内容 | 难度 | 高频 |
|---|---|---|---|
| 数组与字符串 | 双指针、前缀和、差分 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 哈希表 | 计数、O(1) 查找 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 链表 | 虚拟头节点、快慢指针 | ⭐⭐ | ⭐⭐⭐⭐ |
| 栈与队列 | 表达式求值、单调栈引入 | ⭐⭐ | ⭐⭐⭐⭐ |
| 树 | 遍历、BST、LCA | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 堆 | Top-K、堆排序 | ⭐⭐⭐ | ⭐⭐⭐ |
| 图 | BFS/DFS、拓扑排序、最短路径 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
必备算法技巧
| 模块 | 内容 | 难度 | 高频 |
|---|---|---|---|
| 双指针 | 对撞、快慢、归并 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 滑动窗口 | 定长/不定长窗口 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 二分查找 | 边界处理、二分答案 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 分治 | 归并、快排、主定理 | ⭐⭐⭐ | ⭐⭐⭐ |
| 回溯 | 组合/排列/子集模板 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 贪心 | 区间调度、跳跃游戏 | ⭐⭐⭐ | ⭐⭐⭐ |
| 动态规划 | 五步法、空间压缩 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 单调栈 | 下一个更大元素 | ⭐⭐⭐ | ⭐⭐⭐ |
| 并查集 | 路径压缩、按秩合并 | ⭐⭐⭐ | ⭐⭐⭐ |
排序与搜索
| 模块 | 内容 | 难度 | 高频 |
|---|---|---|---|
| 排序算法 | 比较/非比较排序全览 | ⭐⭐ | ⭐⭐⭐ |
| 搜索 | BFS、DFS、A* | ⭐⭐⭐ | ⭐⭐⭐⭐ |
经典问题专题
| 模块 | 内容 | 难度 |
|---|---|---|
| LeetCode Hot 100 精讲 | 高频面试题精选 | ⭐⭐⭐ |
| LRU 缓存 | 哈希 + 双向链表 | ⭐⭐⭐ |
| 股票系列 | 状态机 DP | ⭐⭐⭐⭐ |
| 打家劫舍 | 线性/环形/树形 DP | ⭐⭐⭐ |
| 背包问题 | 0-1/完全/多重背包 | ⭐⭐⭐⭐ |
面试
| 模块 | 内容 | 难度 |
|---|---|---|
| 复杂度分析 | 大 O 表示法、主定理 | ⭐ |
| 面试策略与代码模板 | 五步法、沟通技巧 | ⭐ |
推荐刷题顺序
数据结构基础 → 算法技巧 → 经典问题 → 计时模拟
| | | |
数组/链表 双指针/二分 DP/背包 Hot 100
栈/队列/哈希 滑动窗口 股票/偷盗 面试策略
树/堆/图 分治/回溯 LRU 缓存
贪心/单调栈
并查集题型快速识别表
看到题目后 30 秒内应能识别:
| 题目关键词 | 推荐算法 |
|---|---|
| "两数之和" / "找出对" | 哈希表 / 双指针(排序后) |
| "无重复最长子串" | 滑动窗口 |
| "最长回文" | 中心扩展 / 区间 DP |
| "下一个更大" | 单调栈 |
| "前 K 个" | 堆 / 快速选择 |
| "路径" / "迷宫" | BFS / DFS |
| "依赖关系" / "课程表" | 拓扑排序 |
| "出现次数" | 哈希 / 计数排序 |
| "排序后" | 排序预处理 |
| "动态变化最值" | 单调栈 / 单调队列 |
| "树的最值" | DFS + 后序遍历 |
| "石子合并" | 区间 DP |
| "背包" | 0-1 背包 / 完全背包 |
| "字符串匹配" | KMP / Rabin-Karp |
| "无向图连通" | 并查集 |
| "最短路径" | Dijkstra / Floyd / BFS(无权图) |
| "判断环" | DFS 三色标记 / 拓扑排序 |
面试 vs 竞赛的区别
| 维度 | 面试 | 竞赛 |
|---|---|---|
| 目标 | 展示思维过程和编码能力 | AC 题目数量和速度 |
| 时间 | 40-50 分钟 1-2 题 | 1.5-5 小时 4-10 题 |
| 交流 | 边想边说,展示推理 | 独立思考 |
| 代码风格 | 可读性优先 | 效率优先 |
| 复杂度 | 口述分析 | 隐含在题目约束中 |
| 边界条件 | 必须主动讨论 | 自动判题 |
| 测试用例 | 主动构造 | 系统提供 |
推荐资源
刷题平台
- LeetCode 中文站 — 面试首选,题目按公司/标签分类
- Codeforces — 竞赛训练,算法思维进阶
- 洛谷 — 中文社区,适合入门到进阶
- AtCoder — 日本竞赛平台,题目质量高
- HackerRank — 入门友好,按难度分级
学习资料
- 代码随想录 — 系统刷题教程
- LeetCode 宫水三叶 — 高质量题解
- labuladong 的算法小抄 — 模板总结
- 《算法(第 4 版)》— Sedgewick,Java 描述,入门友好
- 《算法导论》(CLRS) — 学术经典,理论深入
- 《剑指 Offer》— 面试专项
- 《算法设计手册》— Skiena,工程导向
- 《编程珠玑》— Jon Bentley,算法思维训练
视频课程
- MIT 6.006 Introduction to Algorithms — 免费经典课
- Princeton Algorithms — Coursera 上的 Sedgewick 亲授
- B 站灵茶山艾府 — 中文算法讲解
如何复盘
每道题做完后问自己三个问题:
- 这道题的本质模型是什么?(如:滑动窗口求最值)
- 我是怎么从暴力解想到最优解的?(推理链路是否可复用)
- 有哪些边界用例我一开始没考虑到?
建议用 Markdown 或 Anki 记录错题,定期回顾。一道题做三遍,比三道题各做一遍效果好得多。
三遍刷题法
- 第一遍:思考 15 分钟无思路就看题解,理解后自己默写。
- 第二遍(隔 3 天):不看题解,独立完成。卡住时回顾。
- 第三遍(隔 1 周):尝试不同解法,比较优劣,思考变体。
常见题型代码模板速查
双指针(对撞)
python
def template(nums):
l, r = 0, len(nums) - 1
while l < r:
# 处理逻辑
if condition:
l += 1
else:
r -= 1滑动窗口
python
def template(s):
l = 0
cnt = defaultdict(int)
for r in range(len(s)):
cnt[s[r]] += 1
while invalid(cnt): # 窗口不合法时收缩
cnt[s[l]] -= 1
l += 1
# 此刻 [l, r] 是合法窗口二分查找
python
def template(nums, target):
l, r = 0, len(nums) # 注意 r 的取值
while l < r:
mid = (l + r) // 2
if nums[mid] < target:
l = mid + 1
else:
r = mid
return l # 第一个 >= target 的位置BFS
python
from collections import deque
def template(start, target):
queue = deque([(start, 0)])
visited = {start}
while queue:
node, dist = queue.popleft()
if node == target:
return dist
for neighbor in get_neighbors(node):
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, dist + 1))
return -1DFS(回溯)
python
def template(nums):
result = []
path = []
def backtrack(start):
result.append(path[:]) # 收集
for i in range(start, len(nums)):
path.append(nums[i])
backtrack(i + 1)
path.pop()
backtrack(0)
return result动态规划五步法
python
def template(nums):
# 1. 定义状态
dp = [0] * len(nums)
# 2. 初始条件
dp[0] = nums[0]
# 3. 转移方程
for i in range(1, len(nums)):
dp[i] = max(dp[i-1] + nums[i], nums[i])
# 4. 计算顺序:从小到大
# 5. 答案位置
return max(dp)单调栈
python
def template(nums):
stack = [] # 存索引
result = [-1] * len(nums)
for i in range(len(nums)):
while stack and nums[stack[-1]] < nums[i]:
result[stack.pop()] = nums[i]
stack.append(i)
return result并查集
python
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [0] * n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
px, py = self.find(x), self.find(y)
if px == py: return False
if self.rank[px] < self.rank[py]: px, py = py, px
self.parent[py] = px
if self.rank[px] == self.rank[py]: self.rank[px] += 1
return True心态管理
- 刷题焦虑:每个人都觉得自己刷得不够。150-200 题足够大多数面试。
- 记忆遗忘:遗忘是正常的,三遍刷题法解决。
- 看题解挫败:第一次看题解是学习,不是失败。
- 比较心理:不要看别人 AC 多少,按自己节奏走。
- 面试紧张:面试时遇到没见过的题是常态——展现你的思考过程比答对更重要。
30 / 60 / 90 天计划
30 天(150 题)
- 前 10 天:数组、链表、哈希、字符串(50 题)
- 中 10 天:双指针、二分、滑动窗口、回溯(50 题)
- 后 10 天:DP、树、图(50 题)
60 天(250 题)
- 在 30 天基础上增加:LeetCode Hot 100 全部 + 剑指 Offer 全部 + 错题二刷
90 天(350 题)
- 在 60 天基础上增加:Codeforces rating 1400+ 题目 + 公司高频题 100 道 + Mock Interview 20 次