1. 程式人生 > >leetcode 187. Repeated DNA Sequences 編碼計數統計重複字串 + 移動視窗

leetcode 187. 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”].

這道題考察的就是重複出現的字串,這道題給我的啟發很強。

當然,最直接的方法就是暴力求解,但是這個會超時,其實也可以採用HashMap來做(這個方法也可以直接accept),我在網上看到了一個基於編碼的做法,這個做法很棒,直接看程式碼吧!

這道題十分需要注意的地方就是位運算的優先順序,注意所有的位運算以後都注意要新增括號,因為加法的優先順序高於位運算,所以不新增括號是錯誤的。

程式碼如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/*
 * http://blog.csdn.net/xudli/article/details/43666725
 * 
 * 因為只有4個字母,所以可以建立自己的hashkey, 每兩個BITS,
 * 
 * 對應一個 incoming character. 超過20bit 即10個字元時, 只保留20bits.
 * 
 * (hash<<2) + map.get(c)  符號優先順序,  << 一定要括起來.
 * 
 * */
public class Solution { /* * 這個是網上編碼的做法,很不錯的想法,值得反思和學習 * 不過有點麻煩 * */ public List<String> findRepeatedDnaSequencesByCode(String s) { List<String> res=new ArrayList<>(); if(s==null || s.length()<=10) return res; Map<Character, Integer> map=new HashMap<Character, Integer>(); map.put('A', 0); map.put('C', 1); map.put('G', 2); map.put('T', 3); /* * set儲存的是所有的可能的字串, * uniqueSet儲存的的是判斷的重複出現的字串 * 使用uniqueSet是為了避免重複新增重複元素 * */ Set<Integer> set=new HashSet<>(); Set<Integer> uniqueSet=new HashSet<>(); int hash=0; for(int i=0;i<s.length();i++) { Character one=s.charAt(i); if(i<9) hash = (hash<<2) + map.get(one); else { hash = (hash<<2) + map.get(one); hash &= (1<<20)-1; if(set.contains(hash)==false) set.add(hash); else if(set.contains(hash) && !uniqueSet.contains(hash)) { uniqueSet.add(hash); res.add(s.substring(i-9,i+1)); } } } return res; } /* * 使用HashMap去做,這個也很不錯,可以直接accept * * */ public List<String> findRepeatedDnaSequences(String s) { List<String> res=new ArrayList<>(); if(s==null || s.length()<=10) return res; Map<String, Integer> map=new HashMap<>(); for(int i=10;i<=s.length();i++) { String key=s.substring(i-10, i); map.put(key, map.getOrDefault(key, 0)+1); } Set<String> set=map.keySet(); for(String key : set) { if(map.get(key)>=2) res.add(key); } return res; } /* * 暴力去做,這個肯定超時 * */ public List<String> findRepeatedDnaSequencesByLoop(String s) { List<String> res=new ArrayList<>(); if(s==null || s.length()<=10) return res; for(int i=0;i<s.length();i++) { if(i+10<=s.length()) { String one=s.substring(i,i+10); for(int j=i+1;j<s.length();j++) { if(j+10<=s.length()) { if(one.equals(s.substring(j, j+10))) { if(!res.contains(one)) res.add(one); break; } }else break; } } else break; } return res; } }

下面是C++的做法,這道題最直接的方法就是使用map來做查詢,但是可能超時,後來網上看到了一個使用編碼的做法,很棒的做法,值得學習

程式碼如下:

#include <iostream>
#include <algorithm>
#include <climits>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <unordered_map>

using namespace std;

class Solution 
{
public:
    vector<string> findRepeatedDnaSequences(string s) 
    {
        vector<string> res;
        map<char, int> mmp;
        mmp['A'] = 0;
        mmp['C'] = 1;
        mmp['G'] = 2;
        mmp['T'] = 3;
        set<int> st;
        set<int> uniqueSt;
        int hash = 0;
        for (int i = 0; i < s.length(); i++)
        {
            if (i < 9)
                hash = (hash << 2) + mmp[s[i]];
            else
            {
                hash = (hash << 2) + mmp[s[i]];
                hash = hash & ((1 << 20) - 1);
                if (st.find(hash) == st.end())
                    st.insert(hash);
                else if (uniqueSt.find(hash) == uniqueSt.end())
                {
                    uniqueSt.insert(hash);
                    res.push_back(s.substr(i-9,10));
                }
            }
        }
        return res;
    }
};