浅谈算法知识体系
浅谈算法知识体系
在 浅谈算法能力 中,知识和技能被视为能力可以调用的材料。本篇尝试讨论:这些材料应当怎样被组织,才能真正服务于解题、实现和赛场。
我认为,一个完整的算法知识体系需要同时沿两个方向生长。
自顶向下:先建立地图,获得方向和位置感。
自底向上:从真实问题中抽象,建立可靠的工具箱。
前者我称之为 “渗透学习”,后者称之为 “归纳学习”。
自顶向下负责导航,自底向上负责构建。
知识体系的作用
只知道若干算法,不等于拥有知识体系。
孤立的知识只能回答:这个算法叫什么,模板怎么写,曾经在哪道题出现过。而完整的知识体系还需要回答:它在系统中的地位,它的相邻知识点,什么线索能够触发它,它与其他模型有什么共同方法等。
所以我认为,成熟的知识体系应该具备这三个作用:
-
导航:知道有哪些方向,当前处在哪里,下一步可能去哪里。
-
压缩:把大量具体题目和零散的经验串起来,压缩成更少、更稳定的模型和方法。
-
调用:在面对新问题时,根据题目的线索找到可能相关的工具,并知道如何展开、验证和调整。
成熟的知识体系是为了降低未来解决问题时的搜索成本,最终服务的还是人本身。
自顶向下:渗透学习
是在还没有完整掌握一个领域之前,先了解它的名称、位置、用途、核心思想与前后关系,从而建立一张粗略但可用的知识地图。
在进入陌生领域时,如果完全从具体细节开始,很容易出现以下两个问题:
- 不知道当前内容在整个体系中的意义。
- 不知道应当学到什么程度,也不知道后面还有什么。
因此,可以先从上往下了解:它叫什么,它能解决什么问题,它在知识体系中的位置,它依赖哪些前置知识,它连接哪些后续内容,它的核心思想是什么,当前阶段需要掌握多少。
它属于多项式算法;
它主要解决卷积与多项式乘法;
它的核心与求值--插值、单位根和分治有关;
它会连接生成函数,NTT 和更复杂的多项式技术。
此时我们并没有真正掌握 FFT,但已经知道它存在,能够做什么,以及未来遇到什么问题时可能需要回到这里。
渗透学习的作用
-
建立坐标系:知道一个知识点不是孤立存在的,而是存在某条知识链上。
-
提供搜索方向:面对陌生问题时,即使不会具体方法,也能大致判断应该往哪个领域找 “图论”,“动态规划”,“字符串”,“组合数学”,“数据结构”。
-
帮助筛选资源:知道当前需要的是 “地图”,“原理”,“实现”,还是"进阶内容",主导资料的查询,避免被资料牵着走。
-
控制学习深度:不是所有内容都需要立刻深入到底,先知道它的存在和用途,等真实问题出现后再继续下钻。
渗透学习的边界
既然有这么多好处,那坏处呢?
渗透学习法只能建立地图,不能代替正式掌握。
“知道一个算法存在” 与 “能够在题目中识别并使用它” 之间,还有很长的距离。
所以,地图可以自顶向下建立,但正式知识不能仅靠自顶向下填空。否则,就容易形成一套名词很多、层次很漂亮,却无法展开到具体题目和代码的空地图。
注:我的上阶段体系就出现了类似的问题,所以这个问题是真实存在的。
自底向上:归纳学习
是从具体题目、性质、失败和实现经验出发,逐步提取共同结构,把零散事实压缩成模型、方法、机制与思想。
真实的问题提供的往往是具体的经验。
最开始,这些经验往往是不整齐的:可能是某道题的特殊转化,一次错误思考方向,一个实现细节,一个反例,某种数据范围下的优化等。
归纳学习法要做的,就是判断这些零散的经验之间是否存在稳定的共同性质,并逐步将它们抽象,归纳。
- 事实 模型 方法 机制 思想
数学家能找到定理之间的相似之处,优秀的数学家能看到证明之间的相似之处,卓越的数学家能察觉到数学理论之间的相似之处。
而最顶级的数学家能俯瞰这些相似之处之间的相似之处。
A mathematician is a person who can find analogies between theorems; a better mathematician is one who can see analogies between proofs and the best mathematician can notice analogies between theories.
One can imagine that the ultimate mathematician is one who can see analogies between analogies.
工具箱体系
第 0 层:事实层
本层保存最具体的经验:一道题,一个性质,一个反例,一种边界情况等。
例如:
- 环形序列可以复制一遍后线性处理;
- 树状数组下标不能为零;
- 二维偏序中,同值元素的排序顺序会影响严格性;
- 滚动数组更新顺序错误会污染当前状态;
- 某个贪心去掉一个条件后立即失效。
本层的主要作用是提供证据,为上层抽象积累事实支撑。
第 1 层:问题层
问题层整理具有共同结构的一类问题,例如:
- LIS / LCS / 区间 DP / 背包 DP / 最短路 ……
本层的主要作用是:整理这一类问题通常怎样描述和解决。
问题层通常是对一类问题的压缩描述,本质是能抽象出解决这一类问题的通解,而不是缝缝补补加特判。
第 2 层:方法层
方法层是跨越多个专题时,反复出现的关键转化。
比如:前后缀分解,排序降维,二分答案,取补集等。
本层的主要作用是:面对某种障碍时,可以尝试怎样改变问题?
例如,“前后缀分解” 不只属于某一种 DP,它也可以用于判断单个元素的影响、拆分左右贡献、处理删除或强制选择等不同问题中。
方法层是不同专题之间真正产生关联的地方。
第 3 层:机制层
理论上,当多个方法表现出相同本质时,可以进一步抽象为共同的机制。
比如 "改变表示",它包括了 “坐标变换”,“差分”,“取补集”,“建图”,“排序降维” 等,它们本质上都是在原表示隐藏了结构时,寻找一个保持答案但更容易操作的新表示。
机制层的主要作用是:在没有现成模型时,提供一个可供探索的方向。
第 4 层:思想层
这就是最高次的抽象了,往往是一句或几句压缩到极致,但是能概括整个章节的话。
比如:状态应保存影响未来决策的最小必要信息,数据规模也是题目结构的一部分。
这一层很容易写成 “正确的废话”,所以任何高层思想都应该能向下一层一层展开。
如果无法展开到第 0 层或第 1 层,它暂时只能算一种感想,而不能算作完整的工具。
知识体系的结构
五层工具箱描述的是抽象程度,不是说知识体系就是一颗完整的树形结构。
同一道题目可能同时连接很多层的工具,所以成熟的知识体系应该更像一张图,而不是一颗互不交叉的目录树。
注:目录用于存放,整理归档;但链接用于表达关系,适用于调用。
因此,自顶向下和自底向上是会相互影响的过程,完整的循环应该是:
- 顶层地图 指导选择专题、资料与题目 具体问题产生事实与经验 经验抽象为模型 / 方法 多个方法上升为机制 / 思想 高层认知反过来修正知识地图 新地图指导下一轮学习
也就是自顶向下建立地图,自底向上填充工具;具体经验修正高层认识,高层认识再指导新的具体探索。
-
地图:“知道哪里有什么”。告诉自己有哪些方向,提供前后关系,指导资源筛选,帮助确定学习顺序,暂存尚未深入的知识节点。
-
工具箱:“自己真正拥有了什么”。保存经过真是问题验证的经验,压缩重复的结构,建立跨专题链接,提供实际解题时可以调用的模型与方法。
抽象的条件 & 时机
注意!不是每做完一道题,都要立刻向上总结。
一次孤立经验可能只是偶然现象,也可能只是某道题的特殊技巧。
更可靠的归纳通常需要多个相似但不完全相同的案例,能够解释它们的共同结构,说明方法成立的条件与失效边界,并能够迁移到新问题、向下展开到具体证据。
因此,可以采用下面三种处理方式。
-
化归:如果新经验能够直接归入已有模型,就补充现有节点。
-
粘附:如果不能完全归入,但与已有方法存在明确相似性,就建立连接,等待更多案例。
-
暂存:如果暂时无法判断归属,但经验具有独特价值,就先保留在事实层。
不是所有经验都必须,以及立即形成漂亮的理论。
笔记的定位
笔记不是知识体系本身,而是知识体系的外部副本。
它主要记录:容易被遗忘的事实,固定自己的推导与解释,建立节点之间的链接,支持后续修改与压缩等。
不同的笔记需要承担不同层级的任务,而且必须不断更新迭代,初学时,要做加法,补更多的细节、例子、证明和来源,让自己更深刻理解它。理解加深后,要做减法,修正错误,删去重复,压缩已经稳定的内容。
知识层级、知识载体与 Record 生命周期
这里需要区分三个彼此相关、但并不相同的问题。
第一,知识层级回答“这条认识抽象到了什么程度”。前文的事实、问题、方法、机制、思想,就是对知识本身抽象程度的描述。
第二,知识载体回答“这条知识当前由什么承载”。具体题目的 Record 更适合保存真实问题、推导过程、失败、边界和认知变化;Atlas 中的 Topic 更适合压缩已经稳定、可以跨题调用的模型与方法;Guide 和顶层地图则主要负责导航。知识图不是目录树,因此一篇 Record 可以同时连接多个 Topic,一个 Topic 也可以从多篇 Record 中吸收证据。
第三,Record 生命周期回答“一篇具体记录接下来应该怎样演化”。新 Record 在尚未复核时可以保持 pending;完成知识审计后,正式决策只有四种:
retain:Topic 可以吸收其中的稳定知识,但完整 Record 仍保存不可替代的推导、认知修正、多路线比较或跨专题连接;migrate:知识有长期价值,但最终应由更高层 Topic 承载;在 Topic 真正完成吸收以前,原 Record 继续存在;shelved:知识方向已经定位,但当前缺少必要前置或尚未完成真正掌握,应保留缺失前置与回补条件;delete:删除以后不会损失尚未被知识体系接管的有效知识增量。
其中 absorbed、dissolved 等只描述迁移执行到了哪一步,不改变原来的生命周期决策。例如一篇 migrate Record 可以经历 pending → absorbed → dissolved,但它当初为什么被迁移仍然可以追溯。
这三条轴不能混在一起。一个具体题目可以处于事实层,它的稳定模型已经进入某个 Topic,而完整 Record 仍然因为保存了独立认知过程被 retain;也可能一篇已经写完的 Record 被判断为 migrate,等待未来专题真正接管。Future Topic 也只是知识聚类的候选,不能为了清理 Record 而反过来强行创建专题。
因此,学习阶段首先应该如实保存知识增量,而不是急着决定一篇笔记最终以什么形态存在。生命周期判断可以随着 Atlas 的生长延后进行。
还有一条基本原则,笔记的重点应当是自己的理解、推导、连接与补充,而不是重复搬运已经存在的材料。如果书籍,讲义或文章中已经有完全相同的内容,就没必要把它们都 “抄” 进笔记,至少不能把这种 “搬运” 当做写作的根本动机和重点。
这三条原则也可以用来检查自己对内容的理解程度:
- 如果只能照抄教材、复述讲义或搬运 AI 的回答,说明还没有形成自己的理解;
- 如果一个观点没有证明、例子或证据支撑,说明自己的理解还不够深刻、清晰;
- 如果笔记只会增加,不能随着学习被修正、压缩和整理成工具,说明这些内容还没有真正被消化。
总结
算法知识体系,是一套由顶层地图与底层工具共同构成的动态系统:通过渗透学习自顶向下认识方向,通过真实问题自底向上抽象模型与方法,再让两者在不断检验和修正中共同生长。