AC自动机(java)

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自动机的结构.
AC自动机(java)_第1张图片
AC自动机(java)_第2张图片
红色的指针就是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()) {
				// 某个父亲,cur
				cur = 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]);
					}
				}
			}
		}

		// 大文章:content
		public 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

你可能感兴趣的:(算法,数据结构,java,java,开发语言,算法,数据结构,hash-index)