AC自动机算法算是比较简单直观的字符串匹配自动机,它其实就是在一颗Trie树上建一些失配指针,当失配时只要顺着失配指针走,就能避免一些重复的计算。比如对于字符串antibody和tide,如果第一个串匹配到第5个字符(b)失配了可以直接走入第二个串的第3个字符(d)进行匹配,因为前面的“ti”是公共的,如果能匹配到第一个串的第5个字符,那么前面两个肯定是ti。[ Aho-Corasick自动机浅析 AC自动机算法详解
#include <bits/stdc++.h> using namespace std; const int MAXN = 1E5, MAXC = 26; struct node { node * fail; node * nxt[26]; int id; node() { fail = nullptr; fill(nxt, nxt+MAXC, nullptr); id = -1; } }; char keyword[100], s[MAXN]; void insert(const char *s, int id, node *root) { node *p = root; for(int i=0; s[i]!='\0'; ++i) { if(p->nxt[s[i]-'a'] == nullptr) p->nxt[s[i]-'a'] = new node; p = p->nxt[s[i]-'a']; } p->id = id; } void build_fail_point(node * root) { root->fail = nullptr; queue<node*> que; que.push(root); while(!que.empty()) { node * now = que.front(); que.pop(); node * p = nullptr; for(int i=0; i<MAXC; ++i) { if(now->nxt[i] == nullptr) continue; if(now == root) now->nxt[i]->fail = root;//root所有子节点fail指向root else { p = now->fail; while(p != nullptr)//沿着失败指针往上走 { if(p->nxt[i] != nullptr)//直到找到一个存在s[i]子节点的节点 { now->nxt[i]->fail = p->nxt[i];//失败指针指向该子节点 break; } p = p->fail; } if(p == nullptr) now->nxt[i]->fail = root;//没有找到, fail指向root } que.push(now->nxt[i]); } } } vector<pair<int, int>> query(const char *s, node *root) { vector<pair<int, int>> ret; int len = strlen(s); node * p = root; for(int i=0; i<len; ++i) { int index = s[i] - 'a'; while(p->nxt[index] == nullptr && p!=root) p = p->fail;//如果这个字母没有匹配, 沿着失败指针走, //直到匹配或者到root if(p->nxt[index] == nullptr) continue;//没有匹配 p = p->nxt[index]; node * t = p; while(t!=root)//匹配, 沿着这个节点的失败指针, 找到所有以s[i]结尾的节点 { if(t->id != -1) ret.push_back(make_pair(t->id, i)); t = t->fail; } } return ret; } void del(node * root) { for(int i=0; i<MAXC; ++i) if(root->nxt[i] != nullptr) del(root->nxt[i]); delete root; } int main() { node * root = new node; int id = 0; while(cin >> keyword && keyword[0]!='#') insert(keyword, id++, root); build_fail_point(root); cout << " s " << endl; cin >> s; vector<pair<int, int>> v = query(s, root); for(auto x : v) cout << x.first << " " << x.second << endl; return 0; }