问题描述
小C正在研究一种环状的 DNA 结构,它由四种碱基A、C、G、T构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为 n 的碱基序列可以有 n 种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。
例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCA, TCAA, CAAT, AATC,其中 AATC 是字典序最小的表示。
例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCA, TCAA, CAAT, AATC,其中 AATC 是字典序最小的表示。
测试样例
样例1:
输入:
dna_sequence = "ATCA"
输出:'AATC'
样例2:
输入:
dna_sequence = "CGAGTC"
输出:'AGTCCG'
样例3:
输入:
dna_sequence = "TTGAC"
输出:'ACTTG'
def solution(dna_sequence):
# Please write your code here
s = dna_sequence
length = len(s)
s = s + s
f = [-1] * 2 * length
k = 0
for j in range(1, 2 * length):
i = f[j-k-1]
while i != -1 and s[j] != s[k + i + 1]:
if s[j] < s[k + i +1]:
k = j - i - 1
i = f[i]
if s[j] != s[k + i +1]:
if s[j] < s[k]:
k = j
f[j - k] = -1
else:
f[j - k] = i + 1
return s[k:k + length]
通过扩展原始DNA序列来找到最小表示。具体来说,将原始序列 s 复制一次,形成一个长度为 2 * length 的新序列 s + s。然后,使用一个数组 f 来记录前缀匹配的信息,并通过比较不同起点的子序列来找到字典序最小的表示。
以下是思路解释:
思路解释
-
扩展序列:
- 将原始序列
s复制一次,形成s + s。这样做的目的是为了模拟环状结构,使得可以从任何位置开始读取序列。
- 将原始序列
-
前缀匹配数组
f:- 使用一个数组
f来记录前缀匹配的信息。f[i]表示在位置i之前的最长前缀匹配长度。
- 使用一个数组
-
比较和更新:
- 通过遍历扩展后的序列,比较不同起点的子序列,并更新
k的值,使得k始终指向当前找到的最小表示的起始位置。
- 通过遍历扩展后的序列,比较不同起点的子序列,并更新
-
返回结果:
- 最后,从
k位置开始,截取长度为length的子序列作为结果返回。
- 最后,从
代码中的关键步骤
- 扩展序列:
s = s + s - 初始化前缀匹配数组:
f = [-1] * 2 * length - 遍历扩展后的序列:
for j in range(1, 2 * length) - 比较和更新
k:通过i = f[j-k-1]和s[j] != s[k + i + 1]进行比较和更新。