1. 程式人生 > 其它 >187. 重複的DNA序列(經典滑動視窗)

187. 重複的DNA序列(經典滑動視窗)

//20220408
題目描述DNA序列 由一系列核苷酸組成,縮寫為 'A', 'C', 'G' 和 'T'.。
例如,"ACGAATTCCG" 是一個 DNA序列 。
在研究 DNA 時,識別 DNA 中的重複序列非常有用。
給定一個表示 DNA序列 的字串 s ,返回所有在 DNA 分子中出現不止一次的 長度為 10 的序列(子字串)。你可以按 任意順序 返回答案。

解題思路:

  • 使用滑動視窗,用數字來代替字串,我們設定每一個字元為不同的數字(或者用其本身的ASCII值也行,但是這樣會有冗餘,直接相加不行,必須要按照順序使用二進位制),由於每個數字的二進位制碼都不一樣,所以視窗滑動時,如果字串不一樣,則二進位制數字串也不一樣,再把數字加進hashmap,統計每個字串出現的次數即可,大於二的加入結果list

程式碼:

class Solution {

    Map<Character,Integer> dict = new HashMap<>(){{
        put('A',0);
        put('C',1);
        put('G',2);
        put('T',3);
    }};

    public List<String> findRepeatedDnaSequences(String s) {
        List<String> res = new ArrayList<>();
        if(s.length()<=10)return res;
        int x = 0;//滑動視窗
        Map<Integer,Integer> map = new HashMap<>();
        for(int i = 0;i<9;++i){
            //構建初始滑動視窗,只有9個值,最後一個等待正式迴圈時候加入,因為每個字元都是兩位(每個任務不一樣,這裡只有四個字元,所以可以僅僅使用四個數字代表四種字元)
            x = (x << 2) | dict.get(s.charAt(i));//滾動
            System.out.print(s.charAt(i));
        }

        for(int i = 9;i<s.length();++i){
            x = ((x << 2) | dict.get(s.charAt(i)))&((1 << 20) -1);//最後與操作的意義是刪除多餘的視窗(首位)
            map.put(x,map.getOrDefault(x,0)+1);
            if(map.get(x)==2){
                res.add(s.substring(i-9,i+1));
            }
        }
        return res;

    }
}