字符串專題:HDU2222——多串匹配

題目描述:

         給出n個模板串,然後給一個長串,問模板串在長串中出現了多少個。

大致思路:

         應該是一個典型的模板題,用AC自動機就可以搞定。

         但是,鑑於最近學了字符串哈希,那麼就有了一個哈希的想法。首先計算每個模板串的哈希值,存到一個哈希表中,然後枚舉每一個模板串的長度,把長串該長度的所有子串哈希值計算出來,判斷是否出現在哈希表中,如果出現的話就把答案加一。但是字符串哈希之後實在是不會怎麼用hashmap優化,所以只寫出了用AC自動機的做法……當然,AC自動機還是很侷限的,因爲Trie不可能構造的過大,所以對於字符串匹配來說還是沒法滿足大多數需求的。

代碼:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
 
using namespace std;
 
const int M = 510000;
 
struct Trie {
   int ch[M][26],fail[M],end[M],cnt,root;
 
   int NewNode() {
       ++cnt;
       memset(ch[cnt],-1,sizeof(ch[cnt]));
       end[cnt] = 0;
       fail[cnt] = -1;
 
       return cnt;
    }
   void init() {
       cnt = 0; root = NewNode();
    }
   void insert(char s[]) {
       int len = strlen(s), pos = root;
       for (int i = 0; i<len; i++) {
           int val = s[i]-'a';
           if (ch[pos][val] == -1) ch[pos][val] = NewNode();
           pos = ch[pos][val];
       }
       end[pos]++;
    }
   queue<int> Q;
   void get_fail() {
       fail[root] = root;
       for (int i = 0; i<26; i++)
           if (ch[root][i] == -1) ch[root][i] = root;
           else {
                fail[ch[root][i]] = root;
                Q.push(ch[root][i]);
           }
       while (!Q.empty()) {
           int pos = Q.front(); Q.pop();
           for (int i = 0; i<26; i++)
                if (ch[pos][i] == -1)ch[pos][i] = ch[fail[pos]][i];
                else {
                    fail[ch[pos][i]] =ch[fail[pos]][i];
                    Q.push(ch[pos][i]);
                }
       }
    }
   int query(char s[]) {
       int len = strlen(s), pos = root,ans = 0;
       for (int i = 0; i<len; i++) {
           int tmp = ch[pos][s[i]-'a']; pos = tmp;
           while (tmp!=root) {
                ans += end[tmp]; end[tmp] = 0;tmp = fail[tmp];
           }
       }
        return ans;
    }
}AC;
 
char s1[1100000];
 
int main() {
   int t,n;
   cin>>t;
   while (t--) {
       scanf("%d",&n);
       AC.init();
       for (int i = 1; i<=n; i++) {
           scanf("%s",s1);
           AC.insert(s1);
       }
       AC.get_fail();
 
       scanf("%s",s1);
       printf("%d\n",AC.query(s1));
    }
}

發佈了90 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章