187. 重复的DNA序列

112 阅读1分钟

题目:
DNA序列 由一系列核苷酸组成,缩写为 'A''C''G' 和 'T'.。

  • 例如,"ACGAATTCCG" 是一个 DNA序列 。

在研究 DNA 时,识别 DNA 中的重复序列非常有用。

给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。

算法:

方法一:hash table
用hash表存储所有子串,如果出现次数大约2则加入结构。我怎么连这种方法都想不出来。一看到数据范围10^5,不敢用暴力解了,总体时间复杂度O(n),10^5这个数据量还是没问题:

func findRepeatedDnaSequences(s string) []string {
    ans := make([]string, 0)
    subStrCount := make(map[string]int)
    for i := 0; i + 10 <= len(s); i ++ {
        str := string(s[i:i + 10])
        subStrCount[str] ++
        if subStrCount[str] == 2 {
            ans = append(ans, str)
        }
    }
    return ans
}

方法二:hash map + 位运算计算key
对于方法一,可以优化的点在于构造subStrCount的key,str,考虑减少构造hash map key的时间。

var L = 10
var BIN = map[byte]int{'A':0, 'C':1, 'G':2, 'T':3}
func findRepeatedDnaSequences(s string) []string {
    if len(s) < L {
        return nil
    }
    ans := make([]string, 0)
    hashMap := make(map[int]int)
    key := 0
    for i := 0; i < 10; i ++ {
        key = key << 2 | BIN[s[i]]
    }
    // key最长20位
    hashMap[key] ++
    for i := 1; i + L <= len(s); i ++ {
        // 保留低20位
        key = (key << 2 | BIN[s[i + L - 1]]) & (1 << (2 * L) - 1)
        hashMap[key] ++
        if hashMap[key] == 2 {
            ans = append(ans, string(s[i: i + L]))
        }
    }
    return ans
}