AC自动机(Trie图)

来源:互联网 发布:2004美国vs阿根廷数据 编辑:程序博客网 时间:2024/05/21 03:29

传送门

输入
每个输入文件有且仅有一组测试数据。

每个测试数据的第一行为一个整数N,表示河蟹词典的大小。

接下来的N行,每一行为一个由小写英文字母组成的河蟹词语。

接下来的一行,为一篇长度不超过M,由小写英文字母组成的文章。

对于60%的数据,所有河蟹词语的长度总和小于10, M<=10

对于80%的数据,所有河蟹词语的长度总和小于10^3, M<=10^3

对于100%的数据,所有河蟹词语的长度总和小于10^6, M<=10^6, N<=1000

输出
对于每组测试数据,输出一行”YES”或者”NO”,表示文章中是否含有河蟹词语。

样例输入
6
aaabc
aaac
abcc
ac
bcd
cd
aaaaaaaaaaabaaadaaac
样例输出
YES
这个算法搞了两天了,不知道为什么只要和指针有关,我的代码总是有问题,不过总算是解决了吧。。。
注意root的fail一直为null;
终于过去这个坎了…

import java.util.*;public class Main {    static int cnt[]=new int[26];    static Node root=new Node();    public static void main(String[] args)     {        // TODO Auto-generated method stub         Scanner sc=new Scanner(System.in);         int n=sc.nextInt();         while((n--)>0)            insert(sc.next());         build();         if(ACautomation(sc.next()))                 System.out.println("YES");         else             System.out.println("NO");    }    static void insert(String str)    {        Node p=root;        for(int i=0;i<str.length();i++)        {            int x=str.charAt(i)-'a';            if(p.next[x]==null)                p.next[x]=new Node();            p=p.next[x];        }        p.flag=true;    }    static void build()    {        Queue<Node> que=new LinkedList<>();        Node temp=root;        for(int i=0;i<26;i++)            if(temp.next[i]!=null)            {                temp.next[i].fail=root;                que.add(temp.next[i]);            }        while(!que.isEmpty())//构建Trie图        {            temp=que.poll();            for(int i=0;i<26;i++)            {                Node p=temp.next[i];//现在就是找p的fail指针的对象                if(p!=null)//当然只有后代才可以bfs                {                    Node pre=temp.fail;                    while(pre!=null)                    {                        if(pre.next[i]!=null)//这个和写KMP的next数组差不多                        {                            p.fail=pre.next[i];//找到就可以直接break                            if(p.fail.flag)//就是说有别的字符串是这个字符串的子串                                p.flag=true;                            break;                        }                        pre=pre.fail;//找不到就一直去找接下去fail                    }                    if(p.fail==null)说明没有匹配的fail,指向root                        p.fail=root;                    que.add(p);                }            }        }    }    static boolean ACautomation(String  str)    {        Node p=root;        int len=str.length();        for(int i=0;i<len;i++)        {            int x=str.charAt(i)-'a';            for(;;)//这里有for循环的原因当然是因为有多个模式串            {                if(p.next[x]!=null)                {                    p=p.next[x];                    if(p.flag)                        return true;                    break;                }                else                    p=p.fail;                if(p==root||p==null)                {                    p=root;                    break;                }            }        }        return false;    }}class Node{    Node next[]=new Node[26];    Node fail;    boolean flag;}

这个只是简单的寻找是否有匹配串,如果要统计的话,只要稍微修改即可

原创粉丝点击