题目:环状序列表示一般都会有很多种,比如一个环’CCTC’,它的表示方法可能会有很多种,比如,CCTC,CTCC,TCCC,CCCT。这几种表示中,找出字典序最小的表示序列。(字符串只由A、T、G、C四种组成,不含空格)
直接上代码,代码中含思路分析及解答。
此题目还有变体,比如考虑空格后,其实思路解法都是一样的,只是表示时候加入空格字典或者看空格对应ASCII码进行比对排序就好。
"""
Ref:算法竞赛入门经典(第二版)P52例题3-6
求解环状DNA的最小表示(字符串只是由ATGC四种字符串组成)
"""
#coding:utf-8
"""
解法1:时间复杂度O(n^2)
思路:分两步走---
第一:求解出环形DNA所有可能的环状序列,时间复杂度O(n),就是一个字符串拼接问题
第二:对所有的可能环状序列中的每一个序列进行编码,取出最小值对应下标所对应的
环状序列,时间复杂度O(n^2)。优化从此处着手
"""
def circularSequence1(string):
#环状表示
represent = []
for i in range(0,len(string)):
represent.append(string[i:len(string)] + string[0:i])
#从represent找最小的开始点,即把起点找出
#min_number = min(ord('A'),ord('T'), ord('G'), ord('C'))
define_min_number = {'A':'1', 'C':'2', 'G':'3', 'T':'4'}
represent_number = []
rep_number = ''
for rep in represent:
for i in rep:
rep_number = rep_number + define_min_number[i]
represent_number.append(int(rep_number))
rep_number = ''
circular_min = represent[[i for i in range(0,len(represent_number)) if represent_number[i] == min(represent_number)][0]]
return circular_min
"""
解法2:时间复杂度O(n)
思路,将第二步的时间复杂度优化为O(n),去除第一步,将一二步合并为寻找最优开始点:
根据最小表示定义,为字典序最小。所谓字典序,就直接比较两个字符串,
从第一个字符开始比较,当某一个位置的字符不同时,该位置字符较小的串字典序
较小。比如,abc比bcd小;如果其中一个字符串已经结束另一个还没有结束,则先
结束的字符串的字典序较小。例如,hi比history小;
"""
def less(string, p ,q):
n = len(string)
for i in range(0,n):
if string[(p+i)%n] != string[(q+i)%n]:
return string[(p+i)%n] < string[(q+i)%n]
return 0
def circularSequence2(string):
#环状表示
ans = 0 #表示到目前为止,字典序最小串在输入串中的起始位置,然后不断更新ans
# 所以可以直接找字符是否相同
for i in range(0,len(string)):
if less(string, i, ans):
ans = i
results = ''
for i in range(0, len(string)):
results = results + string[(i+ans)%len(string)]
return results
if __name__ == '__main__':
string = ''
string = 'CTCC'
print(circularSequence1(string))
print("\n")
print(circularSequence2(string))
Ref:
算法竞赛入门经典(第二版)P52例题3-6