题目
DNA序列 由一系列核苷酸组成,缩写为 'A', 'C', 'G' 和 'T'.。
例如,"ACGAATTCCG" 是一个 DNA序列 。
在研究 DNA 时,识别 DNA 中的重复序列非常有用。
给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。
示例 1:
输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"
输出:["AAAAACCCCC","CCCCCAAAAA"]
示例 2:
输入:s = "AAAAAAAAAAAAA"
输出:["AAAAAAAAAA"]
提示:
0 <= s.length <= 105
s[i]=='A'、'C'、'G' or 'T'
思路
遍历每一个10位的字符串,统计其出现的次数。因为次数可能持续增加,所以,
判断当次数等于2的时候,就可以把当前的10位字符串加入答案数组。使用一个
10位字符的滑动窗口从左滑到右,遍历所有的10位字符串。字符只有4个,两位二进制
就可以表示。把字符串表示为二进制,滑动窗口的时候,窗口内的10位字符就是20位01串
int有32位,可以使用一个int来表示10位字符串。
代码
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
int L = 10;
int n = s.length();//计算字符串长度
if (n <= L) {//如果字符串长度小于等于10,则没有重复字符串。
return {};
}
vector<string> ans;
unordered_map<char,int> cast = {{'A',0},{'C',1},{'G',2},{'T',3}};//建立映射
int window = 0;
for(int i = 0;i < L - 1;i++) {//前9位的窗口
window = (window << 2) | cast[s[i]];
}
unordered_map<int,int> cnt;
for(int i = 0;i <= n - L;i++) {//从第0位开始遍历第一个10字符,最后一个10字符串从第n-L位开始
//窗口向左移动两位,再或上新的字符,最后右边20位就是新的窗口,因为发生左移,所以还需把从右往左
//第21和22位 置为0。方法是与上20个1
window = ((window << 2) | cast[s[i+L-1]]) & ((1 << (L * 2)) - 1);
if (++cnt[window] == 2) {//等与两次,加入答案
ans.emplace_back(s.substr(i,L));
}
}
return ans;
}
};