输入
每个输入文件有且仅有一组测试数据。
每个测试数据的第一行为一个整数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;
}
这个只是简单的寻找是否有匹配串,如果要统计的话,只要稍微修改即可
c++版
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxx 1000005
using namespace std;
typedef long long ll;
struct AC
{
struct node
{
int nex[26];
int fail;
bool sign;
void init()
{
memset(nex,0,sizeof(nex));
fail=0;
sign=false;
}
}T[maxx];
const int root=1;
int edge=1;
inline void insert(char s[])
{
int now=root;
for(int i=0;s[i];i++)
{
int x=s[i]-'a';
if(T[now].nex[x]==0)
{
T[++edge].init();
T[now].nex[x]=edge;
}
now=T[now].nex[x];
}
T[now].sign=true;
}
queue<int> q;
void build()
{
int tmp=root;
q.push(tmp);
while(q.size())
{
tmp=q.front();q.pop();
for(int i=0;i<26;i++)
{
int p=T[tmp].nex[i];
if(p)
{
int pre=T[tmp].fail;
while(pre)
{
if(T[pre].nex[i])
{
T[p].fail=T[pre].nex[i];
if(T[T[p].fail].sign)
T[p].sign=true;
break;
}
pre=T[pre].fail;
}
if(T[p].fail<=1)T[p].fail=root;
q.push(p);
}
}
}
}
bool query(char s[])
{
int p=root;
for(int i=0;s[i];i++)
{
int x=s[i]-'a';
for(;;)
{
if(T[p].nex[x])
{
p=T[p].nex[x];
if(T[p].sign)return true;
break;
}
else p=T[p].fail;
if(p<=1)
{
p=root;
break;
}
}
}
return false;
}
}ac;
int n;
char s[1000005];
int main()
{
cin>>n;
while(n--)
{
scanf("%s",s);
ac.insert(s);
}
ac.build();
scanf("%s",s);
printf("%s\n",ac.query(s)?"YES":"NO");
return 0;
}