算法基础:打开程序设计之门
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 Aho-Corasick自动机

Aho-Corasick自动机(AC自动机)算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,找出有多少个单词在文章里出现过。要理解AC自动机,先得有Trie树(字典树)和KMP算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针(fail指针),以及模式匹配过程。

2.3.1 Aho-Corasick自动机原理

以典型应用为例,现给定3个单词“china”“hit”“use”,再给定一段文本“chitchat”,求有多少个单词出现在文本中。

(1)根据单词集合{china,hit,use}建立一棵Trie树,如图2.4所示。

图2.4 建立Trie树

(2)根据所给文本“chitchat”依次匹配,图中所示“chi”为匹配成功的字符串,如图2.5所示。

图2.5 匹配成功的字符串

(3)当匹配到第四个字符时,“t”和“n”匹配失败,如图2.6所示。

图2.6 匹配失败

(4)此时知道已匹配成功的字符串为“chi”。

AC算法的核心就是在所有给定的单词中,找到这样的一个单词,使其与已匹配成功字符串的相同前后缀最长,利用这个最长的相同前后缀实现搜索跳转。例如,单词“hit”与已匹配成功字符串“chi”的最长相同前后缀为“hi”,因此下一步从单词“hit”的“t”开始搜索,如图2.7所示。

图2.7 搜索跳转

(5)此时“t”是匹配的,在文本“chitchat”中找到一个单词“hit”。

其实到这里,AC算法的思想已经基本呈现在读者面前了。剩下的问题就是如何解决所述的“核心”。

AC算法的关键:在每个节点里设置一个指针(称之为fail指针),指向跳转的位置。

对于跳转位置的选择,基于以下两点:

(1)对于根节点的所有子节点,它们的fail指针都指向根节点;

(2)而对于其他节点,不妨设该节点上的字符为“ch”,沿着它的父节点的fail指针走,直到走到一个节点,它的子节点中也有字符为“ch”的节点,然后把该节点的fail指针指向那个字符为“ch”的节点。如果一直走到根节点都没找到,则把fail指针指向根节点。

指针跳转如图2.8所示。

图2.8 指针跳转

2.3.2 Aho-Corasick自动机算法的实现

2.3.3 例题讲解

例2-3 Keywords Search

Time Limit:2000/1000 ms(Java/Others) Memory Limit:131072/131072 KB(Java/Others)

题目描述:

给定n个单词以及1个字符串,问字符串中出现了多少个单词(如单词“her”“he”为字符串“aher”中出现了两个单词)。

输入:

第一行输入测试数据的组数,然后输入一个整数nn≤10000),在接下来的n行中每行输入一个单词(每个单词都只包含“a”~“z”,并且单词长度不超过50),最后输入一个字符串(长度不超过1000000)。

输出:

对于每组数据,要输出一行,包含一个整数,该整数表示在字符串中出现了多少个单词。

样例输入:

1

5

she

he

say

shr

her

yasherhs

样例输出:

3

题目来源:HDU 2222。

解题思路:

经典的模板题。