问题描述
科学员正在研究一种环状的 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
简化我们的代码
-
生成所有可能的表示方式:
通过遍历序列的每个位置 i,生成从该位置开始的新序列。
使用取模运算 (i + j) % n 来处理环状结构,确保生成的序列长度为 n。 -
存储所有表示方式:
将生成的所有序列存储在一个集合 dna_sequences_set 中,以确保每个序列只存储一次。 -
找到字典序最小的序列:
使用 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"))