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;}
}