AC自动机
- AC自动机介绍
- 代码演示
- indexTree
AC自动机介绍
AC自动机算法是一种基于Trie树和有限状态机的字符串匹配算法。它在查找字符串时,利用额外的失配指针进行回退,转向其他分支,避免重复匹配前缀,从而提高算法效率。当一个字典串集合是已知的,AC自动机算法可以以离线方式先求出并储存自动机,以便日后使用。在这种情况下,算法的时间复杂度为输入字符串长度和匹配数量之和。AC自动机算法的主要优势是高效、快速,能够在大量文本中快速查找匹配项。
AC自动机算法的流程包括以下几个步骤:
1.构建Trie树:将所有字典串集合中的串进行前缀压缩,得到Trie树。
2.构建Fail指针:从根节点开始,按照字典序遍历所有节点,为每个节点设置Fail指针
3.初始化:将初始状态设为根节点。
4.匹配:从左到右扫描输入字符串,根据当前字符找到下一个节点,并更新Fail指针。如果找到匹配的串,则记录下来。
5.回溯:如果匹配失败,则根据Fail指针回溯到下一个节点重新匹配。
通过以上流程,AC自动机算法可以在O(m+n)时间复杂度内完成字符串匹配,其中m是输入字符串的长度,n是字典串集合中的最长串的长度。
用图演示下AC自动机的结构.
红色的指针就是fail 指针.
代码演示
// 前缀树的节点public static class Node {// 如果一个node,end为空,不是结尾// 如果end不为空,表示这个点是某个字符串的结尾,end的值就是这个字符串public String end;// 只有在上面的end变量不为空的时候,endUse才有意义// 表示,这个字符串之前有没有加入过答案public boolean endUse;public Node fail;public Node[] nexts;public Node() {endUse = false;end = null;fail = null;nexts = new Node[26];}}public static class ACAutomation {private Node root;public ACAutomation() {root = new Node();}public void insert(String s) {char[] str = s.toCharArray();Node cur = root;int index = 0;for (int i = 0; i < str.length; i++) {index = str[i] - 'a';if (cur.nexts[index] == null) {cur.nexts[index] = new Node();}cur = cur.nexts[index];}cur.end = s;}public void build() {Queue<Node> queue = new LinkedList<>();queue.add(root);Node cur = null;Node cfail = null;while (!queue.isEmpty()) {// 某个父亲,curcur = queue.poll();for (int i = 0; i < 26; i++) { // 所有的路// cur -> 父亲 i号儿子,必须把i号儿子的fail指针设置好!if (cur.nexts[i] != null) { // 如果真的有i号儿子cur.nexts[i].fail = root;cfail = cur.fail;while (cfail != null) {if (cfail.nexts[i] != null) {cur.nexts[i].fail = cfail.nexts[i];break;}cfail = cfail.fail;}queue.add(cur.nexts[i]);}}}}// 大文章:contentpublic List<String> containWords(String content) {char[] str = content.toCharArray();Node cur = root;Node follow = null;int index = 0;List<String> ans = new ArrayList<>();for (int i = 0; i < str.length; i++) {index = str[i] - 'a'; // 路// 如果当前字符在这条路上没配出来,就随着fail方向走向下条路径while (cur.nexts[index] == null && cur != root) {cur = cur.fail;}// 1) 现在来到的路径,是可以继续匹配的// 2) 现在来到的节点,就是前缀树的根节点cur = cur.nexts[index] != null ? cur.nexts[index] : root;follow = cur;while (follow != root) {if (follow.endUse) {break;}// 不同的需求,在这一段之间修改if (follow.end != null) {ans.add(follow.end);follow.endUse = true;}// 不同的需求,在这一段之间修改follow = follow.fail;}}return ans;}}
indexTree
数据结构算法:indexTree