1. 程式人生 > >每天一道LeetCode-----尋找給定字串中重複出現的子串

每天一道LeetCode-----尋找給定字串中重複出現的子串

Repeated DNA Sequences

在給定字串中尋找重複出現的序列,每個序列長度為10

可以採用unordered_map記錄每個序列出現的個數,將出現超過一次的新增到結果集中

程式碼如下

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        if(s.size() < 10)   return {};

        vector<string> res;
        unordered_map<string
, int>
hash; size_t first = 0; size_t last = 10; while(last <= s.size()) { auto str = s.substr(first, last - first); if(hash[str] == 1) res.emplace_back(str); ++hash[str]; ++first; ++last; } return
res; } };

但是這種方法每次都需要呼叫substr獲取子串,容易造成效能瓶頸,有什麼方法不用呼叫substr也能判斷當前的這個子串出現過呢

由於規定了子串長度為10,而且子串中只能出現”AGCT“四個字元中的一個,那麼可以考慮用20個bit來表示長度為10的子串,其中每個字元佔兩bit。隨後採用滑動視窗的思想,新到的字元新增到20bit的低位,溢位的字元丟掉

程式碼如下

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        if(s.size() < 10
) return {}; vector<string> res; unordered_map<int, int> hash; int val = 0; /* 掩碼,用於將左溢位的兩位清零 */ int mask = (1 << 20) - 1; /* 每個字元佔兩位,toBit要保證能區分開四個字元 */ for(int i = 0; i < 10; ++i) val = (val << 2) | toBit(s[i]); hash[val] = 1; for(int i = 10; i < s.size(); ++i) { val = ((val << 2) | toBit(s[i])) & mask; if(hash[val] == 1) res.emplace_back(s.substr(i - 10 + 1, 10)); ++hash[val]; } return res; } private: int toBit(char ch) { switch(ch) { case 'A': return 0; case 'G': return 1; case 'C': return 2; case 'T': return 3; } } };