问题描述:
小C正在研究一种环状的 DNA 结构,它由四种碱基A、C、G、T构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为 n 的碱基序列可以有 n 种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。 例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCA, TCAA, CAAT, AATC,其中 AATC 是字典序最小的表示。
实验目的:
研究并实现一个算法,用于找出给定环状 DNA 序列(由四种碱基 A、C、G、T 构成)的字典序最小表示。
实验原理: 一个长度为 n 的环状 DNA 序列可以从任何位置开始读取,因此有 n 种不同的表示方式。我们的目标是找到这些表示中字典序最小的一个。为了实现这一目标,我们可以使用一种称为“字符串的最小表示法”的算法。这种算法的基本思想是通过比较字符串的循环移位来找到字典序最小的移位。
实现步骤:
初始化:将字符串复制一遍并连接到原字符串的后面,形成一个长度为 2n 的新字符串。这样做的目的是为了方便比较字符串的循环移位。比较与选择:使用两个指针 i 和 j,初始时都指向新字符串的起始位置。然后,比较从 i 和 j 开始的两个子串的字典序。如果从 i 开始的子串小于或等于从 j 开始的子串,则将 i 向前移动一位。否则,将 j 向前移动一位,并且如果 j 在某个点回到了起始位置(即 j = 0),则将其设置为 i + 1(因为我们已经知道从 i 开始的子串在当前比较中较小或相等,所以没有必要再比较从 i 开始的子串)。终止条件:当 i 和 j 相遇或 j = i + 1 时,算法终止。此时,从原字符串的 i 位置开始的子串就是字典序最小的表示。
算法分析:
1.初始化结果列表:
创建一个空列表 ans,用于存储所有生成的循环移位。
2.生成循环移位:
利用两层嵌套循环,外层循环变量 i 从 0 遍历至序列长度减 1,代表循环移位的起始位置。内层循环变量 j 同样从 0 遍历至序列长度减 1,用于逐步拼接循环移位后的序列。通过取模运算 (i + j) % len(dna_sequence) 实现循环拼接,确保索引值在有效范围内内循环。 排序并返回结果:对 ans 列表进行排序。返回排序后列表的第一个元素,即字典序最小的循环移位。
- 算法复杂度分析:
时间复杂度: 生成循环移位:由于存在两层嵌套循环,每层循环均遍历序列长度 n 次,因此生成所有循环移位的时间复杂度为 O(n^2)。排序:对 n 个循环移位进行排序,最坏情况下的时间复杂度为 O(n2) 时间,总体时间复杂度主要受生成移位步骤影响。综上,总时间复杂度为 O(n2 log n),但可简化为 O(n2 项主导log n 项的影响较小,但严格意义上应保留 O(n2)。 空间复杂度: 存储所有循环移位需要 O(n^2) 的空间(每个移位长度为 n,共有 n 个移位)。排序过程可能涉及额外空间(具体取决于排序算法的实现)。Python 内置排序通常使用原地排序算法(如 Timsort),因此额外空间开销较小。综上,总空间复杂度为 O(n^2)。
代码实现: