emm
字符串相关的东西···
https://blog.csdn.net/u013371163/article/details/60469534
这个blog讲的很不错诶
然后有两个模板
1、
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 1000010
using namespace std;
int n;
char p[maxn];
queue<int> q;
struct ACA{
int c[maxn][26],val[maxn],fail[maxn],cnt;
void clear(){
memset(c,0,sizeof c); memset(val,0,sizeof val); memset(fail,0,sizeof fail);
}
void insert(char *s){
int len=strlen(s); int now=0;
for(int i=0;i<len;i++){
int v=s[i]-'a';
if(!c[now][v]) c[now][v]=++cnt;
now=c[now][v];//往下找trie树
}
val[now]++;
}
void build(){//构造fail
for(int i=0;i<26;i++) if(c[0][i]) fail[c[0][i]]=0,q.push(c[0][i]);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=0;i<26;i++){
if(c[u][i]) fail[c[u][i]]=c[fail[u]][i],q.push(c[u][i]);
else c[u][i]=c[fail[u]][i];//如果它没有这个儿子,返回它fail的那个节点的这个儿子
}
}
}
int query(char *s){
int len=strlen(s); int now=0,ans=0;
for(int i=0;i<len;i++){
now=c[now][s[i]-'a'];
for(int t=now;t && val[t]!=-1;t=fail[t]){
ans+=val[t]; val[t]=-1;//-1说明统计过了
}
}
return ans;
}
}AC;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",p),AC.insert(p);
AC.build();
scanf("%s",p);
int ans=AC.query(p);
printf("%d\n",ans);
return 0;
}
2、
有 N个由小写字母组成的模式串以及一个文本串T 。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T 中出现的次数最多。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 1000010
using namespace std;
int n;
char p[maxn],s[155][75];
queue<int> q;
struct ACA{
int c[maxn][26],val[maxn],fail[maxn],cnt,tot[maxn];
void clear(){
memset(c,0,sizeof c); memset(val,0,sizeof val); memset(fail,0,sizeof fail); memset(tot,0,sizeof tot);
}
void insert(char *s,int x){
int len=strlen(s); int now=0;
for(int i=0;i<len;i++){
int v=s[i]-'a';
if(!c[now][v]) c[now][v]=++cnt;
now=c[now][v];//往下找trie树
}
val[now]=x;//这里val是这个串的编号
}
void build(){//构造fail
for(int i=0;i<26;i++) if(c[0][i]) fail[c[0][i]]=0,q.push(c[0][i]);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=0;i<26;i++){
if(c[u][i]) fail[c[u][i]]=c[fail[u]][i],q.push(c[u][i]);
else c[u][i]=c[fail[u]][i];//如果它没有这个儿子,返回它fail的那个节点的这个儿子
}
}
}
void query(char *p){//这个地方和下面输出的写重了调了好久···
int len=strlen(p); int now=0,ans=0;
for(int i=0;i<len;i++){
now=c[now][p[i]-'a'];
for(int t=now;t && val[t]!=-1;t=fail[t]){
if(val[t]) tot[val[t]]++;
}
}
for(int i=1;i<=n;i++) ans=max(ans,tot[i]);
printf("%d\n",ans);
for(int i=1;i<=n;i++)
if(tot[i]==ans) printf("%s\n",s[i]);
return;
}
}AC;
int main(){
while(~scanf("%d",&n) && n){
AC.clear();
for(int i=1;i<=n;i++){
scanf("%s",s[i]);
AC.insert(s[i],i);
}
AC.build();
scanf("%s",p);
AC.query(p);
}
return 0;
}