题意:All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.
所有DNA由四种核苷酸构成,分别是A, C, G, T,例如:"ACGAATTCCG"
先需要找到在输入序列中重复出现过的子串,子串长度限定为10。
例如:
Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT", Return: ["AAAAACCCCC", "CCCCCAAAAA"].
值得注意的是输出要求去重,也就是说如果一个子串出现两次及以上,也只输出一次。
思路:
1. 暴力求解
—— 直接将每个子串与后续进行比较,使用标记数组进行标注出现过的子串,如果是第一次重复出现则压入输出res向量。时间复杂度为O(n^2);这个解法经过部分优化还是超时。
2. Hashmap哈希标记
—— 创建hash_map对应字符串和出现频率,<string, int>,对每个出现的子串查找是否存在,如果不存在则插入新的pair,记出现频次为1;如果子串存在哈希表中,判断出现频次是否为1,若为1,则说明本次重复出现是第一次,修改频次为2,并将当前子串压入输出向量。时间复杂度O(n),但是内存超了= =。
3. 压缩字符串+哈希表
—— 注意输入字符串中只会出现四种字符,A, C, G, T,因而可以将它们分别对应为0,1,2,3,二进制分别对应为00,01,10,11,将10位的子串转换为二进制串,只需20位即可表示,使用int型作为哈希的索引,因而哈希表可改建为<int, int>。这里的思路参考了点击打开链接
C++代码如下:
vector<string> findRepeatedDnaSequences(string s) {
vector<string> res;
if(s.size() < 10)
return res;
unordered_map<int, int> DNA;
unordered_map<char, int> types;
types['A'] = 0; types['C'] = 1;
types['G'] = 2; types['T'] = 3;
int key = 0;
for(int i = 0; i<s.size(); i++){
key = ((key << 2) | types[s[i]]) & 0xfffff;
if(i < 9)
continue;
if(DNA.find(key) == DNA.end())
DNA[key] = 1;
else if(DNA[key] == 1){
DNA[key] = 2;
res.push_back(s.substr(i-9, 10));
}
}
return res;
}
运行结果:
注意:需要注意的问题是,Leetcode平台的C++编译环境下没有hash_map,将其替换为unordered_map即可。
欢迎大家一起讨论新思路!