环状DNA序列的最小表示法| 豆包MarsCode AI刷题

22 阅读3分钟

题目

1732364474233.png

代码实现

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序列的最小表示,我们可以使用一种称为“最小表示法”的算法。具体步骤如下:

  1. 复制字符串

    • 将原字符串复制一份并连接到原字符串的末尾,形成一个新的字符串。这样可以方便地处理环状特性。
  2. 双指针法

    • 使用两个指针 i 和 j 分别指向新字符串的起始位置。
    • 比较从 i 和 j 开始的子字符串,直到找到不同的字符或到达字符串末尾。
    • 如果 s[i+k] < s[j+k],则将 j 移动到 j+k+1;否则将 i 移动到 i+k+1
    • 如果 i 或 j 达到原字符串的长度 n,则将另一个指针重置为 0
    • 重复上述步骤,直到 i 和 j 相遇。
  3. 返回结果

    • 最终,i 或 j 中较小的那个就是最小表示的起始位置。
    • 返回从该位置开始的长度为 n 的子字符串。

详细步骤

  1. 复制字符串

    • 将原字符串 dna_sequence 复制一份并连接到原字符串的末尾,形成一个新的字符串 s。这样可以方便地处理环状特性。
  2. 双指针法

    • 初始化指针 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 相遇。
  3. 返回结果

    • min_start = min(i, j):最终,i 或 j 中较小的那个就是最小表示的起始位置。
    • return s[min_start:min_start + n]:返回从该位置开始的长度为 n 的子字符串。

总结与反思

通过上述方法,我们能够高效地找到环状DNA序列的最小表示。这种方法的时间复杂度为 O(n),其中 n 是字符串的长度。双指针法在这里发挥了重要作用,通过比较和移动指针,我们能够快速找到字典序最小的子字符串。