leetcode187. Repeated DNA Sequences

題目要求

All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". 
When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.

Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.

For example,
Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT",

Return:
["AAAAACCCCC", "CCCCCAAAAA"].

全部的DNA都是有A,C,G,T這四個字母組成的,好比「ACGAATTCCG」。在研究DNA的時候,從DNA序列中找到重複出現的模式是頗有用的。這個問題要求咱們在一個DNA序列中找到出現超過兩次的長度爲10的子序列。面試

好比,假設DNA序列爲AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT,那麼找到的知足條件的子序列爲["AAAAACCCCC", "CCCCCAAAAA"]算法

思路一:直接比較String

其實,咱們只須要找到全部的長度爲10的子序列而且判斷這些子序列是否存在重複就能夠了。若是不考慮生成子字符串的過程,那麼這個算法只須要遍歷一次字符串就能夠完成了。
代碼以下:數組

public List<String> findRepeatedDnaSequences(String s) {
        //記錄不是第一次遍歷到的結果
        Set<String> result = new HashSet<String>();
        //記錄第一次遍歷到的結果
        Set<String> visited = new HashSet<String>();
        for(int i = 0 ; i<s.length()-9 ; i++){
            //得到以i做爲起點的長度爲10的字符串
            String cur  = s.substring(i, i+10);
            if(!visited.add(cur)){
                result.add(cur);
            }
        }
        return new ArrayList<String>(result);
    }

思路二:將String轉化爲Integer

上一題的思路其實基本沒有問題,惟一的缺點是,一個長度爲n的字符串可以產生n-9個長度爲10的子字符串。這n-9個子字符串所佔用的空間將會遠遠超過n-9個整數所佔用的空間。若是之間存儲字符串,那麼極可能會形成內存溢出。所以咱們須要考慮將字符串轉化爲整數並存儲。微信

其實若是是將26個字母所有轉化爲整數,並用整數表示任意10個字母所組成的字符串是不可能的。由於26個字母意味着每一個字母至少須要5位才能表示出來。好比00000表明A, 00001表明B。而10個字母意味着須要5*10=50位,而一個整形是32位。ide

而本題中,只有四個字母A,C,G和T,只須要兩位就能夠表示這四個字母,分別是:
A----00----0
C----01----1
G----10----2
T----11----3性能

那麼ACGAATTCCG對應的二進制碼就是00 01 10 00 00 11 11 01 01 10, 再將這個二進制數轉換成對應的十進制數。由於每一個字符串對應的二進制長度爲20,小於整數的32,所以是可行的。spa

代碼以下:code

public List<String> findRepeatedDnaSequences2(String s){
        
        List<String> result = new ArrayList<String>();
        Set<Integer> firstTime = new HashSet<Integer>();
        Set<Integer> secondTime = new HashSet<Integer>();

        //也可使用hashmap,可是用數組的話能夠很好的提高性能
        char[] map = new char[26];
        map['A'-'A'] = 0;//00
        map['C'-'A'] = 1;//01
        map['G'-'A'] = 2;//10
        map['T'-'A'] = 3;//11

        char[] sArray = s.toCharArray();
        for(int i = 0 ; i<sArray.length-9 ; i++){
            int v = 0;
            for(int j = i ; j<i+10 ; j++){
                v <<= 2;
                v |= map[sArray[j] - 'A'];
            }
            
            //這裏使用了短路原理。也就是在字符串被第一次添加到firstTime的時候,將不會觸發secondTime的添加
            //而第二次遍歷時,會觸發secondTime的添加行爲並將子字符串添加到結果集中
            //超過第二次遍歷覺得這secondTime的添加會返回false,說明已經添加過,從而避免了重複添加至結果集
            if(!firstTime.add(v) && secondTime.add(v)){
                result.add(s.substring(i, i+10));
            }
        }
        return result;
        
    }

clipboard.png
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~教程

相關文章
相關標籤/搜索