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