算法总览与工程师心智
学算法最大的坑,不是"题不会做",是搞错了学习姿势——把它当竞赛、当八股、当玄学。工程师学算法的目标和 ACM 选手不一样,跟背面试题的人也不一样。这一篇不教任何具体算法,只解决一个前置问题:你到底为什么要学算法、学到什么程度算够、怎么学最不浪费时间。
一句话先记住:工程师的算法,是为了让你写代码时"直觉正确"——选对数据结构、估对复杂度、读懂别人的代码、在性能出问题时第一反应能定位到"是算法选错了还是实现写挫了"。这个水平离 ACM 金牌远得很,但绝大多数工程师连这个水平都没到。
一、工程师为什么要学算法
先破三个最常见的误解。
误解一:"业务代码用不到算法,学了白学"
错。业务代码天天用——你只是没意识到。往 HashMap 里塞 key、用 Set 去重、sort 一个数组、写分页、查一棵部门树、做权限继承……这些全是算法和数据结构的直接应用。区别只是:你知道底层发生了什么,还是当黑盒用。
当黑盒用短期能跑,长期会挨打:有一天列表从 100 条变成 100 万条,全表 O(n²) 过滤算出来要 30 秒,你一脸懵。懂的人从一开始就会选对数据结构,根本不会有这个 bug。
误解二:"算法就是 LeetCode 刷题,刷够 300 题就行"
错。刷题是练手段,不是目的。刷完 300 题还写不出高质量业务代码的人遍地都是——因为他们把每道题当孤立案例背,没抽出可迁移的心智模型。正确的顺序是:先建模型(这是 DP / 这是滑窗 / 这是图论),再用刷题巩固模型,而不是反过来。
误解三:"算法是面试用,入职就忘"
部分对,但有害。面试是查一个人的"底层硬件"——能不能迅速把陌生问题拆成已知模型。入职后不会让你每天手写快排,但遇到性能问题、设计缓存、做限流、排查慢查询时,没算法底子的人会全程只能 Google,没自己的判断。
二、工程师的三个水位线
| 水位 | 能力 | 对应场景 |
|---|---|---|
| L1:会用 | 知道 HashMap O(1) 查、Array sort O(n log n) | 写业务不写 bug |
| L2:会选 | 场景一来就知道选什么数据结构、避开 O(n²) | 性能不翻车、Code Review 能看出套路 |
| L3:会造 | 读懂 Redis zset / Kafka 消费者组 / HashMap 红黑树化 | 读源码、做架构、解疑难杂症 |
本系列的目标是 L2,顺带摸到 L3 的门槛。L3 往上是 ACM / 做数据库引擎的专属区,绝大多数工程师不需要。
判断自己在哪个水位,有个简单办法:
- 看到一道陌生题,30 秒内说不出大概类别(滑窗?DP?BFS?)→ L1 以下
- 能说出类别,但写不出模板(比如知道是 DP,但定义不出状态)→ L1
- 能写出模板,但边界条件经常错(比如二分写不对
lo <= hi和lo < hi)→ L1.5 - 模板写得熟,但优化想不到(比如能写 O(n²) 但想不到 O(n) 的单调栈)→ L2
- 能看 Linux 内核 / PostgreSQL 源码并读懂里面的数据结构设计 → L3
三、算法学习的"三层抽象"
学算法最低效的做法是"一道题一道题看题解"。正确的做法是按抽象层级吃:
心智模型 ← 可迁移,一辈子管用
↑
算法范式 ← 一类题的套路
↑
具体算法 ← 某道题的解法
↑
代码细节 ← 边界 / 指针 / 下标大多数人卡在最底下两层,永远上不去。上来就背"快排怎么写",写了 50 遍还是写错,因为没建上面两层:
- 你要先理解分治是什么(心智模型)
- 再理解分治在排序里怎么用(算法范式)
- 最后才是快排的具体实现(具体算法)
建好了模型,忘了快排怎么写也没关系——你能从分治的心智里推出来。这就是为什么有人刷 100 题顶别人 1000 题:抽象层次不一样。
四、选对数据结构 = 80% 的算法功夫
工程师 80% 的"算法感"来自数据结构选得对。列个速查表,每一行都是真金白银的经验:
| 需求 | 首选 | 理由 |
|---|---|---|
| 按 key 查值 | HashMap | O(1) |
| 按顺序遍历 + 按 key 查 | TreeMap(红黑树) | 有序 O(log n) |
| 去重 | HashSet | O(1) |
| 去重 + 有序 | TreeSet | O(log n) |
| 先进先出 | Queue / Deque | O(1) |
| 后进先出 | Stack / Deque | O(1) |
| 总是拿最大 / 最小 | PriorityQueue(堆) | O(log n) |
| 按前缀查(自动补全) | Trie | O(前缀长度) |
| 判断某元素有没有见过(允许误判) | BloomFilter | 超省空间 |
| 范围查询(区间和 / 区间最值) | 前缀和 / 线段树 / 树状数组 | O(log n) |
| 连通性 / 分组 | 并查集 | 近 O(1) |
一眼识破:业务同事告诉你"新用户来了给他打标签,老用户就跳过",你听到这句就该立刻反应"HashSet 判存在";他说"最近 10 个访问的 url 要缓存",你立刻想到 "LRU = HashMap + 双向链表"。这就是 L2。
五、算法范式只有八种
工程常用的算法范式没那么多,其实就八种,所有常见题都落在里面:
1. 双指针 / 滑窗 → 线性遍历 + 两个指针夹
2. 二分 → 有序 / 单调性 → O(log n)
3. 排序 + 贪心 → 先排后扫,每步最优
4. 分治 → 分两半递归合并
5. BFS / DFS → 图与树的遍历
6. 动态规划 → 重叠子问题 + 最优子结构
7. 回溯 → DFS + 剪枝,求所有解
8. 拓扑 + 并查集 → 特化图算法记住这八种,再加上三四种数据结构(哈希 / 堆 / 栈 / 队列),80% 题目有套路可抄。这就是为什么算法看起来难,其实有上限。
六、学习路径的三种陷阱
陷阱一:按 LeetCode 编号顺序刷。题号是随机的,你今天碰到 DP,明天碰到图,后天碰到字符串,大脑一直在切换,建不起任何模型。正确的做法:按套路分组集中刷(滑窗类一次刷 10 道,DP 一次刷 15 道)。
陷阱二:刷完题马上看题解。这是"伪勤奋"最大的坑。你大脑根本没真正动过,看完题解觉得"哦这样啊",下次还是不会。至少想够 30 分钟没思路再看题解,看完题解也别抄——关电脑自己默写一遍,错了再打开。
陷阱三:只练不回顾。刷完就丢,一个月后再看题跟没见过一样。每十道题整理一个模板:滑窗模板、二分模板、DP 状态定义模板……这些模板才是你真正带走的东西。
七、本系列的承诺
不堆公式 → 大 O 只讲直觉,不讲主定理证明
不比赛向 → 后缀自动机 / 李超线段树不讲
不按题号走 → 按套路分组,每类讲清楚再往下
每篇独立 → 每篇看完都有个可带走的模板 / 心智图28 篇的硬目标:
- 看完 01-08(心智 + 线性),日常业务代码不再用 O(n²) 写本可 O(n) 的逻辑
- 看完 09-22(树图 + 范式),面试白板题不怵,能识别 80% 题的分类
- 看完 23-28(工程实战),能自己写限流中间件 / LRU 缓存 / 一致性哈希路由
八、一句话总结
算法不是记忆游戏,是抽象训练。你不是在背套路,是在把具体问题抽到已知模型的高度——然后套路就是结果,不是前提。
下一篇讲复杂度——大 O 到底怎么看、什么时候看均摊、为什么哈希表"平均 O(1) 最坏 O(n)"不是自相矛盾。