题目:
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
}