所有 DNA 由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来查找 DNA 分子中所有出现超多一次的10个字母长的序列(子串)。
示例:
输入: s = “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”
输出: [“AAAAACCCCC”, “CCCCCAAAAA”]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/repeated-dna-sequences
刷题还是需要经验的,初看这道题以为考的是kmp算法,往这方面想死活想不出,后来看了题解发现原来只是一个简单的哈希匹配问题。
用10个字符串的滑动框,每滑动一次就将该字符串存入哈希表中,若字符串已经在该表中出现过,即是重复的,时间复杂度O(n),空间复杂度O(kn) =O(n)。
这里想说的是更高级的方法,至少在题解中没怎么出现过。
注意DNA的字母只有A,C,G,T四种,用二进制表示只需要两位00,01,10,11即可区分开,将10个字符串用二进制存到int(32)中也绰绰有余,对,这里说的是面试中能让面试官眼前一亮的位运算:将长10的字符串,每个字符用二进制表示然后存储在一个int数中可以更节省空间,并且中间替换过程进行的位运算也比字符串替换更快。
贴上代码:
class Solution:
def findRepeatedDnaSequences(self, s: str) -> List[str]:
if len(s)<10:
return []
cur=0
mask = 0x7ffffff
pair = {}
res=[]
for i in range(9):
cur = cur<<3 | ord(s[i])&7
for i in range(9,len(s)):
cur = (cur&mask)<<3 | ord(s[i])&7
if cur not in pair:
pair[cur] =1
else:
if pair[cur]==1:
res.append(s[i-9:i+1])
pair[cur]+=1
return res
与上面我所说的用两位二进制表示每个字符不同,我这里用每个字符的ASCLL码的后三位代表它,原理一样。
这里要注意的是两个地方:
1、每添加一个字符,要进行的操作是,cur 左移三位(cur<<3)再或(&)上新来的字符串的后三位(ord(s[i])&7)
2、当10个字符的长度满了,再添加字符需要把前面的字符删掉。这里的mask =0x7ffffff是5个0和27个1,cur&mask 可以用来筛除前面3位的值。
来源:https://blog.csdn.net/juice_panda/article/details/99292053