📌  相关文章
📜  门| Sudo GATE 2020 Mock III(2019 年 1 月 24 日)|第 39 题(1)

📅  最后修改于: 2023-12-03 14:58:33.582000             🧑  作者: Mango

题目介绍

这道题来自 Sudo GATE 2020 Mock III(2019 年 1 月 24 日)的第 39 题。该题目是关于 AC 自动机的应用,要求实现一个门禁系统,其可以检查输入的字符串是否包含在门禁系统的访问列表中。

解题思路

AC 自动机可以用于实现多模式的字符串匹配。AC 自动机的构建包括以下步骤:

  1. 构建 Trie
  2. 添加失败指针(failure link)
  3. 构建成功指针(success link)

在具体实现中,我们先使用 Trie 结构来保存门禁系统的访问列表。在搜索时,从 Trie 的根节点开始,看当前字符是否存在于当前节点的儿子中,存在则进入该儿子节点,否则通过失败指针跳转到 Trie 的某个节点(可以是根节点),重新查找当前字符,直到查找到字符串的末尾。在末尾节点,使用成功指针跳转到其他可以匹配该字符串的节点,进行匹配。

具体实现过程中,我们可以采用队列来维护 Trie 上的节点,以实现 BFS(广度优先搜索)算法来构建 AC 自动机的失败指针和成功指针。BFS 的最后一个步骤是为每个 Trie 上的节点添加它的失败指针和成功指针。

代码实现

下面是 Python 代码实现的一个示例:

import queue

class TrieNode:
    def __init__(self, char=None):
        self.char = char
        self.children = {}
        self.word_finished = False
        self.failure_link = None
        self.success_link = None

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word):
        node = self.root
        for c in word:
            if c not in node.children:
                node.children[c] = TrieNode(c)
            node = node.children[c]
        node.word_finished = True

    def search(self, word):
        node = self.root
        for c in word:
            if c not in node.children:
                return False
            node = node.children[c]
        return node.word_finished

class ACAutomaton:
    def __init__(self, patterns):
        self.trie = Trie()
        for p in patterns:
            self.trie.insert(p)
        self.build()

    def build(self):
        queue = []
        self.trie.root.failure_link = self.trie.root
        queue.append(self.trie.root)

        while queue:
            curr = queue.pop(0)
            for char, child in curr.children.items():
                queue.append(child)
                ptr = curr.failure_link

                while ptr != self.trie.root and char not in ptr.children:
                    ptr = ptr.failure_link
                if char in ptr.children and ptr.children[char] != child:
                    child.failure_link = ptr.children[char]
                elif ptr == self.trie.root:
                    child.failure_link = self.trie.root

                self.success_link(child)

    def success_link(self, node):
        ptr = node.failure_link
        while ptr != self.trie.root:
            if ptr.word_finished:
                node.success_link = ptr
                return
            ptr = ptr.failure_link

    def search(self, text):
        results = []
        curr = self.trie.root
        for i, char in enumerate(text):
            while curr != self.trie.root and char not in curr.children:
                curr = curr.failure_link
            if char in curr.children:
                curr = curr.children[char]
            if curr.word_finished:
                results.append(i)
            slink = curr.success_link
            while slink:
                results.append(i)
                slink = slink.success_link
        return results

patterns = ['hers', 'his', 'she', 'he']
aca = ACutomaton(patterns)
assert aca.search('ushers') == [2, 3]
assert aca.search('uhers') == [3]
assert aca.search('hi') == [0, 2]

以上代码实现了 AC 自动机,包括 Trie 的构建,AC 自动机的失败指针和成功指针的添加,以及用 AC 自动机来搜索输入字符串匹配的过程。