跳转到内容

算法与复杂度

快速概览

算法是解决精确定义问题的指令序列。在生物信息学中,算法不仅是处理数据的工具,更是理解生物过程(如 DNA 复制)的逻辑框架。

  • 通过"石头游戏"理解算法设计与序列比对的内在联系
  • 掌握伪代码描述算法的基本约定
  • 理解时间与空间复杂度(Big-O)在处理大规模生物数据时的重要性
  • 对比生物学算法(如 DNA 复制)与计算机算法的异同
所属板块 基础与数学

对象层、坐标系统、coverage 与概率图模型的共同语言。

阅读目标 帮助建立阅读上下文

先判断这页与你当前问题的关系,再决定是否深入展开。

建议前置 先建立相关基础对象与方法直觉

建议先建立相关基础对象与方法直觉,再进入本页。

1. 算法的直觉:石头游戏(The Rock Game)

Section titled “1. 算法的直觉:石头游戏(The Rock Game)”

想象 Alice 和 Bob 在玩一个游戏:有两堆石头,每堆 10 个。

  • 规则:每轮玩家可以从一堆中拿走一个,或者从两堆中各拿走一个。
  • 目标:拿到最后一个石头的玩家获胜。

Bob 尝试总结规律,但他很快发现当石头数量增加时,情况变得极其复杂。而学过算法的 Alice 画了一张表(如下所示),标记了每个状态 (i,j)(i, j) 是必胜态还是必败态。

0123
0**
1
2**
3

这和生物信息学有什么关系? 这个看似简单的游戏实际上是序列比对(Sequence Alignment) 问题的变体。

  • 拿走一堆的一个石头 \approx 在比对中引入一个空位(Gap)。
  • 从两堆各拿一个石头 \approx 将两个碱基对齐(Match/Mismatch)。
  • 寻找最优策略 \approx 在比对矩阵中寻找最优路径。

如果你不能理解石头游戏的致胜算法,你可能也无法真正理解 BLAST 或 Needle-Wunsch 算法背后的动态规划逻辑。

算法是解决一个精确定义(Well-formulated) 问题的指令序列。它将输入转换为期望的输出。

精确定义
问题必须无歧义。例如"把鞋穿上"对计算机来说太模糊,必须指定"左脚穿左鞋,系好鞋带"。
伪代码(Pseudocode)
介于自然语言和编程语言之间的描述方式,侧重于表达算法逻辑而非语法细节。
子程序(Subroutine)
将复杂问题分解为可复用的功能单元。

在本知识库中,我们使用类似 Python 但更接近数学描述的伪代码:

  • a ← b:赋值操作。
  • for i ← a to b:循环操作。
  • if / else:条件分支。
  • return:返回结果并结束。

大自然本身就在运行”算法”。最典型的例子是 DNA 复制(DNA Replication)

graph TD
subgraph "Biological Process"
Helicase["Helicase (解旋酶)"] -->|"Unwinds"| DNA_Strand["DNA Strand"]
Primase["Primase (引物酶)"] -->|"Starts"| Synthesis["Synthesis (合成)"]
Polymerase["Polymerase (聚合酶)"] -->|"Adds Bases"| Synthesis
Ligase["Ligase (连接酶)"] -->|"Seals"| Result["New DNA"]
end
subgraph "Algorithmic Abstraction"
Read["Read Input String"]
Init["Initialize Pointer"]
Copy["Copy & Append"]
Check["Error Check & Concat"]
end
Helicase --- Read
Primase --- Init
Polymerase --- Copy
Ligase --- Check
步骤生物过程(分子机器)算法抽象
解旋解旋酶(Helicase) 打开双链读取字符串
锚定引物酶(Primase) 放置 RNA 引物初始化指针
合成DNA 聚合酶(Polymerase) 按 3’→5’ 方向合成字符串拷贝/补全
修复酶系统检查错误并由连接酶(Ligase) 补合错误校验与拼接

对于计算机科学家来说,这复杂的分子物流系统可以被抽象为一个简单的 String Duplication Problem:输入一个字符串 SS,输出其副本 SS'

处理生物数据(如 30 亿碱基的人类基因组)时,算法的”快慢”不仅是时间问题,更是”可行性”问题。

我们使用 O(f(n))O(f(n)) 来描述随着输入规模 nn 的增加,运行时间增长的趋势。

graph LR
subgraph "Complexity Hierarchy (Fast to Slow)"
O1["O(1)"] --> OlogN["O(log n)"]
OlogN --> ON["O(n)"]
ON --> ONlogN["O(n log n)"]
ONlogN --> ON2["O(n^2)"]
ON2 --> O2N["O(2^n)"]
end
style O1 fill:#dfd
style ON fill:#fff
style O2N fill:#fdd
记号名称生物信息学示例对 3 Gb 基因组的意义
O(1)O(1)常数级访问数组元素瞬时
O(logn)O(\log n)对数级在排序索引中搜索极快(几十次操作)
O(n)O(n)线性级扫描序列寻找特定 Motif可行(秒级)
O(nlogn)O(n \log n)线性对数级序列排序、构建索引可行(分钟级)
O(n2)O(n^2)平方级两条长序列的精确比对困难 (可能需要数天)
O(2n)O(2^n)指数级穷举所有可能的进化树不可能 (超过宇宙寿命)

描述算法运行所需的内存。例如,一个 n×nn \times n 的比对矩阵需要 O(n2)O(n^2) 的空间,对于人类基因组级别的数据,这会轻易耗尽数百 GB 的内存。

本 Wiki 的后续章节将详细介绍以下核心设计思想:

  1. 穷举搜索(Exhaustive Search):枚举所有可能,适用于规模极小的问题。
  2. 贪心算法(Greedy Algorithms):每步都采取局部最优,简单快速但易陷入局部最优。
  3. 动态规划(Dynamic Programming):利用子问题重叠性,是比对算法的核心。
  4. 分治法(Divide and Conquer):将大问题切分,如快速排序和空间高效的比对。
  5. 随机化算法(Randomized Algorithms):如 Gibbs Sampling,在巨大的搜索空间中”碰运气”。