AC自动机是KMP算法和Trie树的结合,是经典的多模匹配算法。首先将多个模式串构建一棵字典树,然后在字典树上添加失配指针,失配指针相当于KMP算法中的next函数(匹配失败时的回退位置),最后将主串在Trie树上进行模式匹配。
AC自动机算法分为3步:①构建一棵字典树;②构建AC自动机;③进行模式匹配。
1.构建字典树
插入一个字符串时,从前往后遍历字符串,从字典树的根开始判断当前要插入的字符节点是否已存在,若已存在,则沿该分支遍历下一个字符;若不存在,则创建一个新节点表示这个字符。继续遍历其他字符,直到字符串处理完毕。
假设有单词she、he、his、hers,构建一棵字典树。
算法实现
2.构建AC自动机
KMP算法中的next函数(回退函数或者fail函数)。next函数表示S[i]与T[j]不等时j应该回退的位置。
AC 自动机的失配指针有同样的功能,匹配失败时,跳转到当前节点的失配指针所指向的节点,再次进行匹配操作。AC 自动机可以实现多模式匹配,归功于失配指针(fail 指针)。
给字典树的每个节点添加失配指针,AC 自动机就构造完成了。
AC 自动机的失配指针指向的节点代表的字符串是当前节点代表的字符串的最长后缀。
对于当前节点t,t的子指针t->ch[i]分为两种情况:
t->ch[i]不为空:t->ch[i]的失配指针指向t->fail->ch[i]。
t->ch[i]为空:t->ch[i]指向t->fail->ch[i]。
算法步骤:
(1)树根入队。
(2)若队列不为空,则取队头元素t并出队,访问t的每一个子节点t->ch[i]:
t->ch[i]不为空:t->ch[i]的失配指针指向t->fail->ch[i], 并将t->ch[i] 入队。
t->ch[i]为空:t->ch[i]指向t->fail->ch[i]。
(3)队空时,算法结束。
算法实现
3.模式匹配
模式匹配指从树根开始处理模式串的每个字符,沿着当前字符的 fail 指针,一直遍历到u->count=-1为止,在遍历过程中累加这些节点的u->count,累加后将节点标记为u->count=–1,避免重复统计。u->count大于或等于1的节点都是可以匹配的节点。
例如,在字符串shers中包含了几个单词?
算法实现
性能分析
给定k个单词和一段包含n个字符的文章,求有多少个单词在文章里出现过。
若使用KMP算法,则每个模式串Ti都要与主串S进行一次匹配,总时间复杂度为O(n×k+m),其中n为主串S的长度,m为模式串T1,T2,T3,…,Tk的长度之和,k为模式串的个数。而采用AC自动机,时间复杂度只需O(n+m)。