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

122 阅读3分钟

问题描述

小C正在研究一种环状的 DNA 结构,它由四种碱基ACGT构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为 n 的碱基序列可以有 n 种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。

例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCATCAACAATAATC,其中 AATC 是字典序最小的表示。


测试样例

样例1:

输入:dna_sequence = "ATCA"
输出:'AATC'

代码实现

def solution(dna_sequence):
    # Please write your code here
    def process(s):
        s = s + s  # Concatenate
        n = len(s)
        f = [-1] * n  # Failure function
        k = 0  # Least rotation of string found so far

        for j in range(1, n):
            sj = s[j]
            i = f[j - k - 1] 
            while i != -1 and sj != s[k + i + 1]: # 存在可回溯的部分 
                if sj < s[k + i + 1]:
                    k = j - i - 1
                i = f[i]
            if sj != s[k + i + 1]:  # Mismatch after i matches
                if sj < s[k]:  # Found a smaller rotation
                    k = j
                f[j - k] = -1
            else:
                f[j - k] = i + 1

        return s[k:k + len(s) // 2]
    return process(dna_sequence)

基于 Booth's Algorithm,用于快速找到字符串最小表示。

时间复杂度

  1. 字符串拼接s = s + s 这一步的时间复杂度是 O(n),其中 n 是字符串的长度。
  2. 初始化失败函数 f:初始化长度为 2n 的数组 f,时间复杂度是 O(n)
  3. 遍历字符串:外层 for 循环遍历字符串 s,时间复杂度是 O(n)
  4. 内层 while 循环:内层 while 循环用于回溯和比较字符,每次回溯都会减少 i 的值,直到 i 变为 -1 或找到匹配的字符。由于每次回溯都会减少 i 的值,因此内层 while 循环的总时间复杂度是 O(n)

综合以上步骤,整个算法的时间复杂度是 O(n)

空间复杂度

  1. 拼接后的字符串:拼接后的字符串长度为 2n,空间复杂度是 O(n)
  2. 失败函数 f:数组 f 的长度为 2n,空间复杂度是 O(n)

综合以上步骤,整个算法的空间复杂度是 O(n)

总结

基于 Booth's Algorithm 的字符串最小表示算法具有多个优点。首先,其时间复杂度为 (O(n)),意味着算法在处理字符串时能高效地完成任务,无论输入字符串的长度如何。这种线性时间复杂度使得算法在处理大规模数据时依然表现出色,适合实际应用。

其次,算法在空间上的效率也相对较高,空间复杂度为 (O(n))。虽然需要额外的存储来处理拼接后的字符串和失败函数,但这在字符串处理领域是可以接受的。

此外,Booth's Algorithm 的核心思想基于字符比较和回溯,保证了寻找字符串的最小表示时的准确性和有效性。它不仅能处理常规的字符串问题,还可以扩展到其他复杂的字符串操作,具有良好的通用性。综上所述,这种算法在效率和实用性上均展现出显著优势,适合各种字符串处理场景。