【常用算法】AC自动机

背景

ac自动机是为了多模式串匹配,它能在O(n)时间范围内完成多个关键词在一个文档中的快速检索。
其主要原理是应用了 某个关键词的后缀和另一个关键词的前缀相等,那么没有完成关键词1的匹配时就可以直接跳转到另一个关键词的前缀之后开始匹配。
这一跳转主要由字典树中的fail指针完成。

其中fail指针建立的过程通过BFS的方式遍历字典树,当某个节点A的父节点是root时,fail指向父节点。根据父节点->fail转移->fail包含和A相等值的子节点B,把A的fail指向B。
其中检索的过程,发现当前字符char不在p的子节点中时,p指向p的fail,再次检查p是否包含char值的子节点。直到找到包含char的子节点或者p为空。
当char在p的子节点中时,p指向子节点。
当char不在p的子节点时,p指向根节点。
如果发现当前p是在某个关键词的最后一个节点的时候,把关键词所在的下标返回。

代码

class TrieNode:
    def __init__(self,val):
        self.val = val
        self.fail = None
        self.child = {}
        self.tail = 0

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

    def insert(self,word):

        root = self.root
        for c in word:
            if c not in root.child:
                t = TrieNode(c)
                root.child[c] = t
            root = root.child[c]
        root.tail = len(word)

    def build(self):

        queue = [self.root]

        while queue:
            r = queue.pop(0)
            for c in r.child:
                cnode = r.child[c]
                if r == self.root:
                    cnode.fail = self.root
                else:
                    p = r.fail
                    while p:
                        if c in p.child:
                            cnode.fail = p.child[c]
                            break
                        p = p.fail
                    if not p:
                        cnode.fail = self.root
                queue.append(cnode)

    def search(self,text):

        p = self.root
        res = []
        for i in range(len(text)):
            char = text[i]
            ## fail转移
            while p!=self.root and char not in p.child:
                p = p.fail
            ## child转移
            if char in p.child: ## p是root或者其他节点中包含char
                p = p.child[char]
            else: # 不包含char
                p = self.root

            if p.tail >0:
                res.append((i-p.tail+1,p.tail))

        return res

T = Trie()

for w in ["潮汕砂","砂锅粥"]:
    T.insert(w)
T.build()
print(T.search("潮汕砂锅粥"))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值