算法观澜
给我一个循环,什么算不了——这句话,停机之渊记下了。
观澜台上 · 三令牌下注
观澜台悬在万法之上。台下,无数算法如光河流淌——有的湍急,有的缓滞,有的在暗处打转,永不前行。石碑刻着四个字:「效率为尺。」
你嗤笑。算法不就是代码写得快不快?给你一个 for 循环,什么算不了?台角站着一个人影,通体由打孔纸带编织而成——诺依曼老祖。他递过来三块令牌。
「挑一块最好的。」他的声音像机器咬合,没有任何温度。「你敢把直觉押上去吗?」
「最快的最好。」深渊在台下低语。「我替你记账。每一笔,S9 清算。」
三令牌下注 · 逐一执行,看各自的代价
三块令牌各刻一段伪代码。逐一执行——有的快但错,有的对但慢,有的对且快但吃内存。👆 点击「下注·执行」
三槽定义发现 · 把三块令牌的代价拖入对应的维度
详解 · K05-01 算法的概念与衡量尺度:正确性、时间、空间
算法 = 有限、确定、可行的指令序列,且必须终止。正确性是第一公民:对一切合法输入给出正确输出——大数溢出截断的"闪电法"再快也不是算法。时间与空间是第二、三把尺,二者常可互换:哈希表以空间换时间,归并排序用 O(n) 额外空间买 O(n log n) 的确定性——"时空权衡"是贯穿全部算法设计的母题。唯有正确性不可交易。衡量一个算法,永远三把尺一起拿出来。(CLRS Ch1)
渐近之尺 · 大O的诞生
尺子入手冰凉。刻度不是数字,是函数。台下光河中浮出九个函数球——1、log₂n、√n、n、n log₂n、n²、n³、2ⁿ、n!——在无标度的虚空中乱作一团。
「把它们从小到大排好。」
「100n² 比 n³ 大得多,不是应该排前面?」
九函数排序 · 按增长率从小到大排到渐近之尺上
点击函数球,按增长率从小到大依次排入尺槽。排错会震动提示。
渐近之尺
三符号槽 · O / Ω / Θ 的定义
详解 · K05-02 渐近记号:O / Ω / Θ 的定义与运算性质
形式定义:O(g) = { f(n) : ∃c,n₀>0,n≥n₀ 时 0 ≤ f(n) ≤ c·g(n) }——渐近上界;Ω(g) 把不等号反向——渐近下界;Θ(g) = O(g) ∩ Ω(g)——紧界。运算性质:常数因子与低阶项被吸收(100n²+n = Θ(n²)),且有对偶律 f=O(g) ⇔ g=Ω(f)。注意"f=O(g)"的等号是惯例滥用,应读作"f 属于 O(g)"——渐近记号描述的是函数集合的归属关系,不是等式。排序九函数的那把尺(1 < log n < √n < n < n log n < n² < n³ < 2ⁿ < n!)值得背到条件反射。(CLRS Ch3)
量劫仪 · 三种天命
量劫仪是一座三面棱镜,内部悬浮着一段快排伪代码。
「快排。你给它什么,它就是什么命。」
你不信。快排不就是 O(n log n)?尺子上写着的。棱镜第一面亮了——你喂进去一个已排好序的数组。光河猛地滞住,像撞上一堵墙。
三面棱镜 · 喂不同输入,看快排的三种命运
点击下方按钮,逐一喂入三种输入,点亮三面棱镜。
详解 · K05-03 时间/空间复杂度分析:最坏 / 平均 / 最好情形
同一个算法,复杂度是输入的函数:最坏情形给出"保证"(工程承诺的锚点),平均情形给出"期望"(必须声明输入分布假设),最好情形几乎没有工程意义。快排是最好的教材:已排序输入 + 固定 pivot 退化为 O(n²),随机输入期望 O(n log n)。随机化 pivot 的深意:把"倒霉的输入"转化为"倒霉的随机数"——期望复杂度从此与输入分布无关,敌人无法再针对性投喂最坏数据。分析空间复杂度同理(递归深度即栈空间,快排最坏 O(n) 栈)。(CLRS Ch3 / Ch7)
分形塔 · 递归的代价
分形塔的每一层都是上一层的缩影——递归的物理化身。塔壁刻着一行递推方程:T(n) = aT(n/b) + f(n)。
「搭一棵递归树,看看每层花多少。」他递来一面镜子——递归之镜,镜框铭刻「映树」。
你心想:分治嘛,二分两半再合并,不就 O(n log n)?你在镜面上写下 T(n) = 2T(n/2) + n²——合并那一步是 n²,你以为无所谓。镜中的递归树长出来了。你数了数每层的总和——n² + n²/2 + n²/4 + …… = 2n²。不是 n log n。是 n²。塔壁裂了一道缝。
递归树 + Master 定理 · 四个递推归类
切换四个预设递推,看递归树每层总和,自动归类到 Master 三区域。
Master 定理三区域
详解 · K05-04 分治策略与递推方程:代入法 / 递归树 / Master 定理
分治递推 T(n) = aT(n/b) + f(n):a 个子问题、规模 n/b、合并代价 f(n)。三种解法各有分工:代入法先猜后用数学归纳法验证(本章陷阱递推取 c≥2 证明闭合);递归树逐层求和,几何级数的走向直接暴露主导项;Master 定理比较 f(n) 与分水岭 n^(log_b a):f 小→叶主导 Θ(n^(log_b a)),相等→每层均摊 Θ(n^(log_b a)·log n),f 大→根主导 Θ(f(n))(Case 3 还需正则条件 a·f(n/b) ≤ c·f(n))。Strassen 矩阵乘把 a 从 8 压到 7,Θ(n^2.807) 就此打败朴素 n³——分治的艺术全在"怎么切、怎么合"。(CLRS Ch4)
排序刑场 · 不可逾越的下界
排序刑场是一片开阔的石台。诺依曼老祖:「排好它们。比 O(n log n) 更快。」你不信邪。冒泡太慢?换快排。快排最坏 O(n²)?换堆排。堆排也是 O(n log n)?换归并——还是 O(n log n)。你试了五种排序,没有一种低于 n log n。
「换更聪明的排序,总能比 n log n 快——是吗?」
刑场中央升起一棵巨树——不是递归树,是判定树。每个节点是一次比较,每条路径是一种排列结果。
五排序竞速 + 判定树下界 · Ω(n log n)
拖 n 滑块看五条曲线全部卡在 n log n 以上;展开判定树数叶子;Stirling 展开确认下界。
判定树论证
详解 · K05-05 排序算法谱系与比较排序下界 Ω(n log n)
排序谱系的取舍矩阵:插入/冒泡 O(n²) 但简单稳定;归并 O(n log n) 稳定、可外排,代价是 O(n) 空间;快排期望 O(n log n) 原地但不稳定;堆排 O(n log n) 原地但不稳定。比较排序下界:任何基于比较的排序对应一棵判定树,n! 种输入排列必须各占一片叶子 ⇒ 树高 ≥ log₂(n!),Stirling 展开得 Θ(n log n)——这是信息论下界,与聪明无关。要更快只有跳出"两两比较"模型:计数排序、基数排序、桶排序利用键值的额外结构可达 O(n),但它们不是通用排序。(CLRS Ch6–8)
散列阁 · O(1)的幻象
散列阁里悬着无数小格,每格有自己的编号。诺依曼老祖递给你一个哈希函数:「把数据丢进去,算个地址,直接放。不比较,不排序。」
你试了——O(1)。丢一个,查一个,都是 O(1)。你笑了:「这就是答案。排序下界?那是比较排序的下界。我不比较。」然后你丢进了第一百个数据。两个数据算出了同一个地址。格子里撞了。
哈希表模拟 · 冲突 + 摊还分析
点击插入数据,看冲突如何发生;拖入恶意输入看退化;展开摊还分析。
详解 · K05-06 哈希表:冲突处理与平均 / 摊还分析
哈希表把"比较"换成"计算地址",期望 O(1)。冲突处理两大路线:链地址法(每格挂链表,平均查找 O(1+α),α=n/m 为装载因子)与开放寻址(线性/二次/双重哈希探查,期望探查数 ≈ 1/(1−α),α 必须 < 1)。平均 O(1) 的前提是全域哈希的均匀性假设——对手若能构造同哈希键(哈希洪水攻击),查找退化为 O(n),这正是真实世界 DoS 的手段。摊还分析:表倍增下插入均摊 O(1),因为 rehash 总代价是几何级数 m+2m+…+n < 2n;三种分析工具——聚合分析、记账法、势能法——是 CLRS Ch17 的三件套。(CLRS Ch11 / Ch17)
贪心迷阵 · 局部最优的陷阱
贪心迷阵的每条岔路口都写着「取最优者行」。第一关活动选择——每步选最早结束的,完美。第二关 Huffman 编码——每步合并频率最低的,完美。你笑了:「每步取最优,全局就最优。」
第三关——0-1 背包。容量 10,三件宝物:重 6 值 12、重 5 值 10、重 5 值 10。你按性价比选了最贵的——重 6 值 12。剩 4 的空间,什么都装不下了。总计值 12。
「另一条路:选两件重 5 值 10——总重 10,总值 20。你每步都选了最优。你的结果比最优差了 40%。」
贪心三关 · 活动选择 → Huffman → 0-1 背包
关卡1:点击活动条选最早结束的;关卡2:构建 Huffman 树;关卡3:看贪心翻车。
关卡1 · 活动选择(选最早结束)
关卡2 · Huffman 编码
频率 {5,9,12,13,16,45}。每步合并最低两棵子树。
关卡3 · 0-1 背包(容量 10)
贪心成立需同时满足:①最优子结构 ②贪心选择性质。0-1 背包满足①不满足②——选了重6后堵死了后续。
详解 · K05-07 贪心算法思想:贪心选择性质与局部最优
贪心成立需要两根支柱同时立住:①最优子结构(最优解包含子问题最优解)②贪心选择性质(存在包含贪心选择的最优解——局部最优"安全")。活动选择(选最早结束,CLRS 16.1 原例 11 活动最优 4 个)与 Huffman 编码(合并最低频,可证前缀码最优)都满足②;0-1 背包满足①不满足②——选了重 6 值 12 就堵死两件重 5 值 10 的组合(12 vs 20);而分数背包(可切割)却满足②,贪心反而正确。验证贪心的标准武器是交换论证(exchange argument):证明任一最优解都能"换"进贪心选择而不变差——证明缺位时,贪心只是启发式。(CLRS Ch16)
记忆之殿 · 重叠的代价
记忆之殿的墙壁上刻满了格子——每一个格子是一个子问题的答案。你在墙上写下递推:OPT(i, w) = max{ OPT(i-1, w), OPT(i-1, w-wᵢ) + vᵢ }。格子逐个填满,最优解 20 浮现。你笑了:「DP。天下无敌。」
递过递归之镜——第二次了。镜面铭刻已变:「映图」。「现在解这个。」他在镜上写下:TSP。
S 是已访问城市的子集。子集有多少?2ⁿ。10 个城市,1024。15 个,32768。20 个——一百万。墙壁裂了。
DP 表格填充 + TSP 状态爆炸
0-1 背包 DP(3 件物品,W=10)
TSP 状态爆炸 · 2ⁿ·n 计数器
详解 · K05-08 动态规划思想:最优子结构与重叠子问题
DP 的两大适用条件:最优子结构(最优解由子问题最优解组装)+重叠子问题(子问题被反复求解,值得记忆)。实现两路线:自顶向下备忘录(递归+缓存)与自底向上填表(按拓扑序迭代)。0-1 背包递推 OPT(i,w) = max{ OPT(i-1,w), OPT(i-1,w-wᵢ)+vᵢ } 填出最优 20,复杂度 O(nW) 是伪多项式——W 按输入位长算是指数级。TSP 的 Held-Karp DP 状态为(已访问子集, 当前城市),2ⁿ·n 个状态:子问题确实重叠,但状态空间本身指数膨胀,记忆也救不了。DP 的能力边界 = 子问题 DAG 的规模。(CLRS Ch15)
迷图深渊 · 路径与遍历
迷图深渊是一张巨网——节点如星辰,边如暗河。你吐出一口气。BFS——队列推进,一层一层扫开。DFS——深入到底再回溯。两种走法,O(V+E)。掌控感回来了。
你开始找最短路径——Dijkstra,贪心地取最近节点。干净利落。然后,一条边亮起了暗红色。它的权重是负的。Dijkstra 的光河在那条边前停住了。
「慢一点。Bellman-Ford。什么路都走得通。」
你以 O(VE) 的代价走完了负权图。但当你走到最深的那个节点——脚下的网碎了。下面是深渊。深渊里传来一个声音:「它会停吗?」
图遍历 + 最短路径 · BFS/DFS/Dijkstra/Bellman-Ford
详解 · K05-09 图的遍历:BFS / DFS 及其应用
BFS 与 DFS 同为 O(V+E),是图算法的两大母结构。BFS(队列,按层推进):天然给出无权图最短路径,还可做二分图判定、层序分析。DFS(栈/递归,深入回溯):拓扑排序、连通/强连通分量、环检测的基石——发现时间 d 与完成时间 f 构成括号化区间(括号化定理),边的分类(树边/回边/前向边/横边)全部由此读出。选 BFS 还是 DFS,取决于你要"最近的答案"还是"最深的结构"。(CLRS Ch22)
详解 · K05-10 最短路径算法:Dijkstra 与 Bellman-Ford
Dijkstra:贪心 extract-min + 边松弛,堆实现 O((V+E) log V)。正确性论证的关键一步是"节点出队即封盘"——这依赖非负权假设;负权边可以让已封盘的距离变得更小,论证当场击穿,这正是注入负权边后 Dijkstra 给错答案的原因。Bellman-Ford:放弃贪心,对全部边做 V-1 轮松弛,O(VE) 换负权容忍;第 V 轮仍能松弛 ⇒ 存在负权环(本章"检测负权环"按钮即此原理)。选型口诀:非负单源 Dijkstra,负权单源 Bellman-Ford,全源 Floyd-Warshall O(V³),稀疏图全源 Johnson。(CLRS Ch24)
停机之渊 · 三问排除法收网
深渊没有底。它不是黑暗——它是「无法判断」本身。它开口了,声音像无数程序同时在执行又同时卡死:
「你以为更快的算法能解决一切。我来告诉你——有些问题,不是慢。是不存在答案。三问。答得出来,我退。答不出来——你留在渊底。」
递出递归之镜——第三次,铭文已变:「映己」。「你的刻痕,够用了。」
渊账累计 0 笔 · 三问全对后清零
算法观澜 · 计算的边界
观澜台回到脚下。你低头看——石板上的五道刻痕亮了。五道刻痕拼成一幅地图。不是迷路的图——是边境的图。
「你来了的时候说:给我一个循环,什么算不了。现在你知道了。有些东西,算不了。不是因为你不够能干——是因为它们不在计算的范围里。这不是退步。这是你第一次看见了世界的形状。」
知识图谱点亮 · 十二碎片排认知链
点击下方碎片,按因果顺序点亮认知链。
五刻痕回顾 · 触碰刻痕,回闪对应场景
递归之镜三阶段
三层计算边界地图
详解 · K05-11/12 P/NP/NP 完全与不可计算性:三层边界复盘
P = 多项式时间可解;NP = 多项式时间可验证(给证书能核验);NP 完全 = NP 中"最难"的一批——Cook-Levin 定理证明 SAT 是第一个 NP 完全问题,此后一切 NP 完全结论都靠多项式归约接力(SAT → 3-SAT → 团 → 顶点覆盖 → TSP…)。P=NP?千禧年难题,悬而未决——但多数研究者押 P≠NP。不可计算是更深的墙:停机问题不可判定,对角化构造 D(D) 让任何候选判定器 H 自指矛盾(Turing 1936),且由 Rice 定理,程序的任何非平凡语义性质都不可判定。三层边界收束本章:效率边界 Ω(n log n)(定理砌的)→ 复杂性边界 NP 完全(可能砌的)→ 可计算性边界停机(必然砌的)。下一章 ch06 硅基咒语:从算法的抽象世界回到机器——用硬件描述语言把逻辑钉进硅片。(CLRS Ch34 / Sipser Ch4/7)