小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
187. 重复的DNA序列
所有 DNA 都由一系列缩写为 'A','C','G' 和 'T' 的核苷酸组成,例如:"ACGAATTCCG"。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来找出所有目标子串,目标子串的长度为 10,且在 DNA 字符串 s 中出现次数超过一次。
- 示例 1:
输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 输出:["AAAAACCCCC","CCCCCAAAAA"]
- 示例 2:
输入:s = "AAAAAAAAAAAAA" 输出:["AAAAAAAAAA"]
解题思路
使用滑动窗口+位运算
- 使用Map可以在O(1)的时间复杂度内获得目标子串出现的次数
- 但是因为0 <= s.length <= 100000,因此如果使用map统计长度为 10的目标子串,空间复杂度非常高。但是因为所有 DNA 都由一系列缩写为 'A','C','G' 和 'T' 的核苷酸组成,所以我们可以使用2位二进制表示一个字符,那么长度为10的目标子串也就只需要一个32位的整型来表示
- 朴素的解法中,需要枚举所有长度为10的目标子串,时间复杂度为o(10*s.length),我们可以使用滑动窗口,维护窗口内的字符串组成,时间复杂度为o(s.length)
代码
class Solution {
public String decode(int tar) {
StringBuilder sb = new StringBuilder();
for (int i=0;i<10;i++)
{
int cur=tar&3;
if (cur==0)
sb.append('A');
else if(cur==1)
sb.append('C');
else if(cur==2)
sb.append('G');
else sb.append('T');
tar>>=2;
}
return sb.reverse().toString();
}
public int count(char c) {
if (c=='A')
return 0;
else if(c=='C')
return 1;
else if(c=='G')
return 2;
else return 3;
}
public List<String> findRepeatedDnaSequences(String s) {
ArrayList<String> strings = new ArrayList<>();
Map<Integer,Integer> map=new HashMap<>();
int cur=0,l=0,r=0,n=s.length(),mask=(1<<20)-1;
while (r<n)
{
if (r-l>=10)
{
map.put(cur,map.getOrDefault(cur,0)+1);
cur-=(count(s.charAt(l++))<<18);
}
cur<<=2;
cur+=count(s.charAt(r++));
}
map.put(cur,map.getOrDefault(cur,0)+1);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue()>1)
strings.add(decode(entry.getKey()));
}
return strings;
}
}