思路:
- 构造新的字符串:为了模拟环状结构,我们将原字符串
s拼接两次,形成一个新的字符串s + s。这样,所有可能的子串都可以在新的字符串中找到。 - 找到最小表示的起始位置:遍历所有可能的起始位置(从 0 到
n-1),找到字典序最小的子串的起始位置。 - 返回最小表示:从找到的起始位置截取长度为
n的子串,即为最小表示。
代码实现
Python
深色版本
def solution(dna_sequence):
def compute_kmp_table(s):
n = len(s)
kmp = [0] * n
j = 0
for i in range(1, n):
while j > 0 and s[i] != s[j]:
j = kmp[j - 1]
if s[i] == s[j]:
j += 1
kmp[i] = j
return kmp
n = len(dna_sequence)
concatenated = dna_sequence + dna_sequence
kmp = compute_kmp_table(concatenated)
min_index = 0
for i in range(1, n):
if concatenated[i:i+n] < concatenated[min_index:min_index+n]:
min_index = i
return concatenated[min_index:min_index+n]
if __name__ == "__main__":
print(solution("ATCA") == "AATC")
print(solution("CGAGTC") == "AGTCCG")
print(solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG") == "AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG")
代码详解
-
compute_kmp_table:
- 这个函数用于计算 KMP 算法中的 next 数组。虽然在这个问题中我们没有直接使用 next 数组来匹配字符串,但它帮助我们在构造的
s + s字符串中找到最小表示的起始位置。 kmp[i]表示前缀s[0:i+1]的最长公共前后缀的长度。- 通过双指针
i和j来填充kmp数组。
- 这个函数用于计算 KMP 算法中的 next 数组。虽然在这个问题中我们没有直接使用 next 数组来匹配字符串,但它帮助我们在构造的
-
构造新的字符串:
concatenated = dna_sequence + dna_sequence:将原字符串拼接两次,形成一个新的字符串s + s,这样可以模拟环状结构。
-
找到最小表示的起始位置:
- 初始化
min_index为 0。 - 遍历所有可能的起始位置(从 1 到
n-1),比较每个子串concatenated[i:i+n]和当前最小的子串concatenated[min_index:min_index+n]。 - 如果当前子串的字典序更小,更新
min_index。
- 初始化
-
返回最小表示:
- 从找到的起始位置
min_index截取长度为n的子串,即为最小表示。
- 从找到的起始位置