浅谈AC自动机(Aho-Corasick automaton算法)

前置技能

KMP&&Trie

AC自动机简介

AC自动机全称Aho-Corasick automaton算法,是1975由贝尔实验室发明的一种多模式匹配的算法。常用于给定多个模式串并要求匹配的一类问题中。

算法介绍

我们先由一个问题开始:给出m个字符串,再给出一个字符串S,问,S中出现了多少次前面给出的字符串?
根据我们以往的做法,除了暴力,一个比较容易想到的做法就是先把m个字符串插入到一棵Trie中,然后枚举S中的起点,并在Trie中匹配,最后把答案加起来。但是显然,这样的做法对于|S|较大的情况是很不靠谱的,那么这个时候我们就想到,我们每一次枚举过程中,都没有对之前的匹配过的位置的信息利用起来,而利用之前的匹配信息来优化匹配过程,正是KMP的算法思想。综上,我们就开始思考,能不能通过某种方式,让字符串在Trie上匹配的过程能够像KMP一样提高时间效率呢?这就是AC自动机的朴素描述,即在Trie上做KMP。

算法流程

我们首先用最开始的m个字符串建立Trie,每一个节点包含,然后就到了AC自动机最经典的部分,fail指针的构造。这个fail指针就相当于KMP算法中的next数组,它表示了如果当前发生了失配,下一个匹配的位置就是当前节点的fail指向的位置。举个栗子。
我们有5个字符串,分别是:
she
he
say
shr
her
包含这5个字符串的字典树的形状为:
这里写图片描述
我们回想一下,KMP算法中的next数组就是表示的与当前后缀匹配的最长前缀,同样的,这里的fail指针也是表示的是和当前节点表示的后缀匹配的最长前缀的位置(这里有点绕,多想一下就好了)。我们可以用BFS找出每一个节点的fail指针指向的位置。显然,根节点以及与根节点直接相连接的点的fail指针是指向根节点的,其余节点则是从其父节点的fail指针指向的位置出发,一直到当前节点存在表示这个字符的子节点或者到根节点为止。代码如下(这里用数组代替STL中的queue):

void Build(){
    int now,t,head=0,tail=0;
    q[tail++]=0;
    a[0].fail=0;
    while(head!=tail){
        now=q[head++];
        for(int i=0;i<26;i++)//26代表字符有26if(a[now].nxt[i]){
                for(t=a[now].fail;t&&!a[t].nxt[i];t=a[t].fail);
                if(now)
                    a[a[now].nxt[i]].fail=a[t].nxt[i];
                q[tail++]=a[now].nxt[i];
            }
    }
}

所以样例最后构建出的AC自动机如下(虚线代表fail指针):
这里写图片描述
匹配过程则是和KMP算法类似,如果与当前节点匹配成功,就继续向子节点匹配,如果不成功,则沿着fail指针继续匹配。其余细节与Trie基本相同。
练习题:
HDU2222
HDU2896
HDU5880

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值