题目
代码实现
def solution(dna_sequence):
# Please write your code here
n = len(dna_sequence)
s = dna_sequence + dna_sequence # 复制字符串
i, j, k = 0, 1, 0
while i < n and j < n and k < n:
if s[i + k] == s[j + k]:
k += 1
else:
if s[i + k] > s[j + k]:
i = i + k + 1
else:
j = j + k + 1
if i == j:
j += 1
k = 0
# 找到最小表示的起始位置
min_start = min(i, j)
return s[min_start:min_start + n]
if __name__ == "__main__":
# You can add more test cases here
print(solution("ATCA") == "AATC")
print(solution("CGAGTC") == "AGTCCG")
print(solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG") == "AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG")
问题描述
小C正在研究一种环状的DNA结构,它由四种碱基A、C、G、T构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为n的碱基序列可以有n种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。
解决方案
为了找到环状DNA序列的最小表示,我们可以使用一种称为“最小表示法”的算法。具体步骤如下:
-
复制字符串:
- 将原字符串复制一份并连接到原字符串的末尾,形成一个新的字符串。这样可以方便地处理环状特性。
-
双指针法:
- 使用两个指针
i和j分别指向新字符串的起始位置。 - 比较从
i和j开始的子字符串,直到找到不同的字符或到达字符串末尾。 - 如果
s[i+k] < s[j+k],则将j移动到j+k+1;否则将i移动到i+k+1。 - 如果
i或j达到原字符串的长度n,则将另一个指针重置为0。 - 重复上述步骤,直到
i和j相遇。
- 使用两个指针
-
返回结果:
- 最终,
i或j中较小的那个就是最小表示的起始位置。 - 返回从该位置开始的长度为
n的子字符串。
- 最终,
详细步骤
-
复制字符串:
- 将原字符串
dna_sequence复制一份并连接到原字符串的末尾,形成一个新的字符串s。这样可以方便地处理环状特性。
- 将原字符串
-
双指针法:
- 初始化指针
i和j分别指向新字符串的起始位置,k用于记录当前比较的位置。 - 使用
while循环,比较从i和j开始的子字符串,直到找到不同的字符或到达字符串末尾。 - 如果
s[i+k] < s[j+k],则将j移动到j+k+1;否则将i移动到i+k+1。 - 如果
i或j达到原字符串的长度n,则将另一个指针重置为0。 - 重复上述步骤,直到
i和j相遇。
- 初始化指针
-
返回结果:
min_start = min(i, j):最终,i或j中较小的那个就是最小表示的起始位置。return s[min_start:min_start + n]:返回从该位置开始的长度为n的子字符串。
总结与反思
通过上述方法,我们能够高效地找到环状DNA序列的最小表示。这种方法的时间复杂度为 O(n),其中 n 是字符串的长度。双指针法在这里发挥了重要作用,通过比较和移动指针,我们能够快速找到字典序最小的子字符串。