算法笔记写作规范
目标
算法笔记默认按 labuladong 风格整理:先讲问题和思路,再拆解状态/选择/遍历顺序,最后只保留 Go 代码,确保复习时能快速想起“为什么这样想、为什么这样写、为什么不会错”。
总体要求
- 默认使用问题驱动的讲法,不从 API 或语法开始。
- 默认只保留 Go 示例,不再混用 Python、C++、Java 等多语言并排展示。
- 代码前先解释状态、变量、不变量和关键选择,避免“上来先贴模板”。
- 能抽象成通用框架的算法,优先总结成「套路 + 例题 + Go 模板」。
- 优先解释“为什么这样定义/为什么这样遍历/为什么这样剪枝”,这部分比代码本身更重要。
推荐结构
1. 一句话说明
用一句普通话解释算法:
- 二分查找:每次扔掉一半不可能的位置。
- 动态规划:把重复出现的小问题保存下来,后面直接查表。
- Dijkstra:每次确认当前离起点最近的点,再用它更新邻居距离。
这一段要尽量口语化,像 labuladong 文章开头那样,让读者先建立直觉。
2. 适用场景
写清楚什么时候用、什么时候不能用:
- 数据是否有序。
- 边权是否非负。
- 每个物品能选一次还是能重复选。
- 问的是最大值、最小值、可行性还是方案数。
3. 原理
用生活化解释先讲直觉,再给正式定义。推荐先回答下面几个问题:
- 这道题暴力做法是什么,瓶颈在哪。
- 为什么这个算法能减少搜索范围或避免重复计算。
- 每一步做出的“选择”为什么不会漏掉答案。
- 关键不变量是什么。
推荐写法:
## 核心思路
先用一句话说明直觉。
## 为什么这样设计
解释这个选择为什么不会漏答案,为什么能减少计算。4. 实现方式
不要只贴代码,先说明变量含义:
| 变量 | 含义 |
|---|---|
left / right | 当前还可能有答案的范围 |
dp[j] | 容量为 j 时的最优结果 |
stack | 还没找到答案的一批候选元素 |
dist[x] | 起点到 x 的当前最短距离 |
5. 为什么这样实现
重点解释最容易忘的地方:
- 二分为什么用
left <= right或left < right。 - 0-1 背包为什么一维数组要逆序遍历。
- 完全背包为什么一维数组要正序遍历。
- 单调栈为什么被弹出的元素不会再成为答案。
- Dijkstra 为什么不能处理负权边。
- KMP 为什么失配时模式串可以跳到
next[j]。
如果是动态规划、回溯、树递归,尽量补出 labuladong 常用的三个视角:
- 状态是什么。
- 可选操作是什么。
- base case 是什么。
6. 图解
优先使用 Mermaid、表格、ASCII 图或 SVG。简单流程用 Mermaid,局部状态变化用表格,复杂结构可以补 SVG。
flowchart LR A[问题] --> B[定义状态] B --> C[状态转移] C --> D[初始化] D --> E[遍历顺序] E --> F[返回答案]
6.1 动画
只有状态连续变化时才使用动画,例如排序交换、二分区间收缩、BFS 队列扩展。动画统一放在 附件/算法可视化/,例如使用 (附件 binary-search.gif 未随站点发布) 嵌入。
动画不能代替静态解释:同一篇笔记仍应保留状态表、Mermaid 或文字步骤,便于暂停阅读、全文搜索和打印。
7. Go 代码
代码块统一使用 go:
## Go 代码
```go
func solve(...) ... {
// ...
}
```要求:
- 同一篇笔记默认只保留 Go 示例。
- 如果需要多个版本,优先保留「基础版 + 优化版」两个 Go 实现,不再额外附 Python/C++ 对照。
- 函数名、变量名尽量贴近题意,少用过度抽象的
foo、bar。 - 复杂代码前可以加 1 到 2 行简短注释,重点解释不容易一眼看懂的转移、剪枝或数据结构维护。
8. 复杂度和坑点
复杂度要说明来源,而不是只写结论:
- 时间复杂度为什么是
O(n log n)。 - 空间复杂度主要消耗在哪里。
- 哪些输入会退化。
- 哪些边界条件最容易错。
题解补充模板
## 为什么想到这个算法
- 题目里的关键词:
- 暴力解法的问题:
- 该算法能优化的点:
## 状态 / 变量含义
| 名称 | 含义 |
|------|------|
| | |
## 执行过程图解
```mermaid
flowchart LR
```
## Go 代码
```go
func solve(...) ... {
}
```
## 易错点
- 检查清单
- 是否用一句话讲清楚算法在做什么。
- 是否说明适用条件和不适用条件。
- 是否把暴力思路与优化思路的差异讲清楚。
- 是否明确状态、选择、base case 或关键不变量。
- 是否解释核心变量含义。
- 是否解释关键边界和遍历顺序的原因。
- 是否只保留 Go 代码示例。
- 是否有图解、表格或状态变化示例。
- 是否说明复杂度的来源。
返回:算法学习导航