A C AC AC 自动机( A h o − C o r a s i c k a u t o m a t o n Aho-Corasick \ automaton Aho−Corasick automaton)在1975年产生于贝尔实验室,是著名的多模匹配算法。
学习AC自动机之前,首先要有 K M P KMP KMP 和 T r i e Trie Trie(字典树)的基础知识。
我们先用 n n n 个模式串构造一颗 T r i e Trie Trie , T r i e Trie Trie 中的一个节点表示一个从根到当前节点的字符串。
如果节点是个模式串,打一个标记。
void insert(char* s) {
int p = 0;
for (int i = 0; s[i]; i ++ ) {
int j = s[i] - 'a';
if (!tr[p][j]) tr[p][j] = ++ idx;
p = tr[p][j];
}
cnt[p] ++ ;
}
在 T r i e Trie Trie 上构建两类边:回跳边、转移边。
n e [ i ] ne[i] ne[i] :
c h [ u ] [ i ] ch[u][i] ch[u][i] :
用BFS构造 A C AC AC 自动机:
void build() { //创建 AC 自动机
queue<int> q;
for (int i = 0; i < 26; i ++ ) {
if (tr[0][i]) q.push(tr[0][i]);
}
while(q.size()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; i ++ ) {
int v = tr[u][i];
if (v) ne[v] = tr[ne[u]][i], q.push(v);
else tr[u][i] = tr[ne[u]][i];
}
}
}
扫描主串,依次取出字符 s [ k ] s[k] s[k] :
int query(char* s) {
int ans = 0;
for (int i = 0, k = 0; s[k]; k ++ ) {
i = tr[i][s[k] - 'a'];
for (int j = i; j && ~cnt[j]; j = ne[j]) {
ans += cnt[j];
cnt[j] = -1;
}
}
return ans;
}
参考资料:
1、《算法训练营进阶版》— 陈小玉
2、b站董晓算法