Python解决“环状DNA序列的最小表示法”问题

Python解决“环状DNA序列的最小表示法”问题

问题描述

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

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

测试样例

样例1:
输入:dna_sequence = “ATCA”
输出:‘AATC’

样例2:
输入:dna_sequence = “CGAGTC”
输出:‘AGTCCG’

样例3:
输入:dna_sequence = “TTGAC”
输出:‘ACTTG’

解决思路

这道题目综合运用了字符串处理和集合数据结构的知识,是一道典型的字符串最小表示问题。
题目要求找到一个环状 DNA 序列的最小字典序表示。由于环状结构可以从任意位置开始读取,因此一个长度为 n 的序列可以有 n 种不同的表示方式。我们需要从这些表示中找到字典序最小的序列。为了实现这一点,我们可以生成所有可能的表示方式,并将它们存储在一个集合中,然后从中找到字典序最小的序列。

时间复杂度:
生成所有可能的表示方式需要 O(n^2) 的时间复杂度,因为我们需要遍历每个位置并生成一个长度为 n 的序列。使用 min 函数在集合中查找最小值的时间复杂度为 O(n),因为集合的大小为 n。
因此,总的时间复杂度为 O(n^2)。

空间复杂度:
存储所有可能的表示方式需要 O(n^2) 的空间复杂度,因为每个位置生成的序列都需要存储。
因此,总的空间复杂度为 O(n^2)。

代码

法1

current_sequence < min_sequence比较规则:

  • current_sequence < min_sequence 是通过逐个比较序列中的元素来判断的。
  • 如果 current_sequence 在某个位置的元素小于 min_sequence 对应位置的元素,则 current_sequence < min_sequence 为 True。
  • 如果所有对应位置的元素都相同,但 current_sequence 的长度小于
    min_sequence,则 current_sequence < min_sequence 也为 True。
def solution(dna_sequence):
    n = len(dna_sequence)
    # 复制序列以生成所有可能的表示
    extended_sequence = dna_sequence + dna_sequence
    # print(extended_sequence)
    min_sequence = dna_sequence  # 初始化最小序列为原序列
    # print(min_sequence)
    # 遍历所有可能的表示
    for i in range(1, n):
        current_sequence = extended_sequence[i:i+n]
        # print(current_sequence)
        # 如果当前序列比最小序列小,更新最小序列(这个比较是逐位比较,所以可以直接比较)
        if current_sequence < min_sequence:
            min_sequence = current_sequence
    
    return min_sequence

if __name__ == "__main__":
    # 你可以添加更多测试用例
    print(solution("ATCA"))
    print(solution("CGAGTC"))
    print(solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG"))

输出:
AATC
AGTCCG
AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG

法2

简化我们的代码

  1. 生成所有可能的表示方式:
    通过遍历序列的每个位置 i,生成从该位置开始的新序列。
    使用取模运算 (i + j) % n 来处理环状结构,确保生成的序列长度为 n。

  2. 存储所有表示方式:
    将生成的所有序列存储在一个集合 dna_sequences_set 中,以确保每个序列只存储一次。

  3. 找到字典序最小的序列:
    使用 min 函数结合 key=lambda x: (x, len(x)) 来找到集合中字典序最小的序列。
    由于集合中的序列长度相同,len(x) 只是为了确保 min 函数能够正常工作。

def solution(dna_sequence: str) -> str:
    dna_sequences_set = set()
    n = len(dna_sequence)

    for i in range(n):
        new_sequence = ''.join(dna_sequence[(i + j) % n] for j in range(n))
        dna_sequences_set.add(new_sequence)

    dna = min(dna_sequences_set, key=lambda x: (x, len(x)))
    return dna


if __name__ == '__main__':
    print(solution(dna_sequence = "ATCA"))
    print(solution(dna_sequence = "CGAGTC"))
    print(solution(dna_sequence = "TTGAC"))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥都鼓捣的小yao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值