leetcode 187.findRepeatedDnaSequences(位运算)

所有 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位的值。

你可能感兴趣的:(算法)