【187中等】重复的DNA序列(2021.10.8)
1. 问题描述
所有 DNA 都由一系列缩写为 'A'
,'C'
,'G'
和 'T'
的核苷酸组成,例如:"ACGAATTCCG"
。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来找出所有目标子串,目标子串的长度为 10,且在 DNA 字符串 s
中出现次数超过一次。
示例1:
输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"
输出:["AAAAACCCCC","CCCCCAAAAA"]
示例2:
输入:s = "AAAAAAAAAAAAA"
输出:["AAAAAAAAAA"]
提示:
0 <= s.length <= 105
s[i]
为'A'
、'C'
、'G'
或'T'
2. 思路
-
要注意边界条件(字符串长度不满10)
遍历原来字符串中长度为10的字串,使用map来存储字符串出现的次数,滑动窗口
最后返回出现次数超过1的字串
-
编码,位运算,很巧妙,值得学习,
3. 代码
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
int n = s.size();
if(n < 10) {
return {};
}
map<string, int> map;
vector<string> result;
string temp = "";
for(int i = 0; i < n - 9; i++) {
temp = s.substr(i, 10);
map[temp]++;
}
for(auto iter = map.begin(); iter != map.end(); iter++) {
if(iter -> second > 1) {
result.push_back(iter -> first);
}
}
return result;
}
};
思路一致,写法有优化:
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
vector<string> ans;
unordered_map<string, int> count;
for (int i = 0; i <= int(s.size()) - 10; i++) {
string str = s.substr(i, 10);
count[str]++;
}
for (auto &it : count) {
if (it.second >= 2)
ans.push_back(it.first);
}
return ans;
}
};
作者:bianchengxiong
链接:https://leetcode-cn.com/problems/repeated-dna-sequences/solution/acmjin-pai-ti-jie-you-xiao-dai-ma-10xing-b2gu/
采用位运算
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
//对应二进制00, 01, 10, 11.那么10个组合只要20位就够了。
unordered_map<char, int> m{{'A', 0}, {'C', 1}, {'G', 2}, {'T', 3}};
vector<string> res;
bitset<1 << 20> s1, s2; //那么所有组合的值将在0到(1 << 20 - 1)之间
int val = 0, mask = (1 << 20) - 1; //mask等于二进制的20个1
//类似与滑动窗口先把前10个字母组合
for (int i = 0; i < 10; ++i) val = (val << 2) | m[s[i]];
s1.set(val); //置位
for (int i = 10; i < s.size(); ++i) {
val = ((val << 2) & mask) | m[s[i]]; //去掉左移的一个字符再加上一个新字符
if (s2.test(val)) continue; //出现过两次跳过
if (s1.test(val)) {
res.push_back(s.substr(i - 9, 10));
s2.set(val);
}
else s1.set(val);
}
return res;
}
};
4. 复杂度
时间复杂度: O(n),n表示字符串的长度