AC自动机

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 AhoCorasick automaton)在1975年产生于贝尔实验室,是著名的多模匹配算法。

学习AC自动机之前,首先要有 K M P KMP KMP T r i e Trie Trie(字典树)的基础知识。

1、构造 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] ++ ;
}
2、构造 A C AC AC 自动机

T r i e Trie Trie 上构建两类边:回跳边、转移边。

  • 回跳边指向父节点的回跳边所指节点的儿子。
  • 转移边指向当前节点回跳边所指节点的儿子。转移边相当于 K M P KMP KMP 的失配指针。

n e [ i ] ne[i] ne[i]

  • 存节点 v v v 的回跳边的终点。
  • 回跳边指向父节点的回跳边所指节点的儿子。
  • 四个点 ( v , u , n e [ u ] , c h [ ] [ ] v, u, ne[u], ch[ ][ ] v,u,ne[u],ch[][]) 构成四边形。
  • 回跳边所指节点一定是当前节点的最长后缀

c h [ u ] [ i ] ch[u][i] ch[u][i]

  • 既存树边的终点也存转移边的终点。
  • 三个点( u , n e [ u ] , c h [ ] [ ] u,ne[u],ch[][] u,ne[u],ch[][])构成三角形。
  • 转移边所指节点一定是当前节点的最短路

BFS构造 A C AC AC 自动机:

  • 初始化把根节点的儿子们入队。
  • 只要队不空,节点 u u u 出队,枚举 u u u 26 26 26 个儿子
    • 若儿子存在,则爹帮儿子建回跳边,并把儿子入队。
    • 若儿子不存在,则爹自建转移边。
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];
        }
    }
}
3、扫描主串匹配

扫描主串,依次取出字符 s [ k ] s[k] s[k]

  • i i i 指针走主串对应的节点,沿着树边或转移边走,保证不回退。
  • j j j 指针沿着回跳边搜索模式串,每次从当前节点走到根节点,把当前节点中的所有后缀模式串—网打尽,保证不漏解。
  • 扫描完主串,返回答案。
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站董晓算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值