zoukankan      html  css  js  c++  java
  • AC自动机

    AC自动机

    image

    1.根据字符构造trie树
    2.构建失败匹配指针
       1.根节点的所以一代子孩子失败指针都指向root
       2.子节点匹配失败时,找到父节点的失败指针,找不到就一直找,直到找到root还匹配不到,直接指向root
    3.文本串匹配
       1.如果已经匹配到完整的模式串或者压根匹配不到,根据失败指针切换线路继续向下查找
       2.如果匹配到了,那么就继续向下匹配
    
    class ACNode {
        constructor(data){
            this.data = data
            this.isEndingChar = false
            this.children = new Map()
            this.length = 0
            this.fail = null
        }
    }
    
    class ACTree {
        constructor(){
            this.root = new ACNode('/')
        }
        insert(text){
            let node = this.root
            for(let char of text ){
                if(!node.children.get(char)){
                    node.children.set(char,new ACNode(char))
                }
                node = node.children.get(char)
            }
            node.isEndingChar = true
            node.length = text.length
        }
        failurePointer(){
            let root = this.root
            let queue = []
            queue.push(root)
            while(queue.length > 0){
                let currentNode = queue.shift()
                for(let child of currentNode.children.values()){
                    if(!child){
                        continue
                    }
    
                    if(currentNode == root){
                        child.fail = currentNode
                    }else{
                        //不是一代子节点才指向
                        let grandFatherNode = currentNode.fail
                        while(grandFatherNode){
                            let failNode = grandFatherNode.children.get(child.data)
                            if(failNode){
                                child.fail = failNode
                                //找到失败节点就不往下找了
                                break
                            }
                            grandFatherNode = grandFatherNode.fail
                        }
                        if(!grandFatherNode){
                            child.fail = root
                        }
                    }               
                    queue.push(child)
                }
            }
        }
        match(text){
            let root = this.root
            let len =  text.length
            let currentNode
            for(let i = 0; i < len; i++){
                let char = text[i]
    
                if(!currentNode){
                    currentNode = root
                }
    
                while(!currentNode.children.get(char) && currentNode != root){
                    //匹配不到就换线
                    currentNode = currentNode.fail
                }
    
                currentNode = currentNode.children.get(char)
    
                let tmp = currentNode
                while(tmp != root){
                    if(tmp.isEndingChar){
                        console.log(`from ${i - tmp.length + 1} length: ${tmp.length} str: ${text.substr(i - tmp.length + 1,tmp.length)}`)
                    }
                    //匹配到了就继续看看其他线有没有可以匹配成功的
                    tmp = tmp.fail 
                }
    
            }
        }
    }
    
    function match(text,patterns){
        const autoMeta = new ACTree()
        for(pattern of patterns){
            autoMeta.insert(pattern)
        }
        autoMeta.failurePointer()
        autoMeta.match(text)
    }
    
    let patterns = ["at", "art", "oars", "soar"];
    let text = "soarsoars";
    match(text, patterns);
    
    let patterns2 = ["Fxtec Pro1", "谷歌Pixel"];
    let text2 = "一家总部位于伦敦的公司Fxtex在MWC上就推出了一款名为Fxtec Pro1的手机,该机最大的亮点就是采用了侧滑式全键盘设计。DxOMark年度总榜发布 华为P20 Pro/谷歌Pixel 3争冠";
    match(text2, patterns2);
    
  • 相关阅读:
    洛谷 P4114 Qtree1
    洛谷 P2486 [SDOI2011]染色
    洛谷 P1505 [国家集训队]旅游
    洛谷 P4281 [AHOI2008]紧急集合 / 聚会
    C++中main函数的返回值一定要是int
    局部变量作为函数返回值
    sizeof和strlen在string类中的使用
    strlen 和 sizeof 的区别
    数据结构中的堆栈和内存中的堆栈问题
    数据类型的字长,字节问题
  • 原文地址:https://www.cnblogs.com/pluslius/p/10810471.html
Copyright © 2011-2022 走看看