跳转到内容

算法与复杂度

快速概览

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

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

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

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

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

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

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

| | 0 | 1 | 2 | 3 | ... | |---|---|---|---|---|---| | 0 | * | ← | * | ← | ... | | 1 | ↑ | ↘ | ↑ | ↘ | ... | | 2 | * | ← | * | ← | ... | | 3 | ↑ | ↘ | ↑ | ↘ | ... |

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

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

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

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

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

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

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

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

| 步骤 | 生物过程(分子机器) | 算法抽象 | | :--- | :--- | :--- | | 解旋 | 解旋酶(Helicase) 打开双链 | 读取字符串 | | 锚定 | 引物酶(Primase) 放置 RNA 引物 | 初始化指针 | | 合成 | DNA 聚合酶(Polymerase) 沿模板 3'→5' 方向读取,按 5'→3' 方向合成新链 | 字符串拷贝/补全 | | 修复 | 酶系统检查错误并由连接酶(Ligase) 补合 | 错误校验与拼接 |

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

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

我们使用 O(f(n))O(f(n)) 来描述随着输入规模 nn 的增加,运行时间增长的趋势。从快到慢:O(1)O(logn)O(n)O(nlogn)O(n2)O(2n)O(1) \to O(\log n) \to O(n) \to O(n \log n) \to O(n^2) \to O(2^n)

| 记号 | 名称 | 生物信息学示例 | 对 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,在巨大的搜索空间中"碰运气"。