多模匹配算法
模板题:
给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。(hdu2222)
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e6+7;
int a[maxn][26],fail[maxn],cnt[maxn]; //字典树,失败时的回溯指针,记录该单词出现次数
int tot,rt,n;
string sz;
void insert(string s){
rt=0;
int len=s.size();
for(int i=0;i<len;i++){
int k=s[i]-'a';
if(!a[rt][k]) a[rt][k]=++tot;
rt=a[rt][k];
}
cnt[rt]++;
}
void getfail(){
queue<int>q;
for(int i=0;i<26;i++) if(a[0][i]) q.push(a[0][i]);
while(!q.empty()){
int x=q.front(); q.pop();
for(int i=0;i<26;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}
else a[x][i]=a[fail[x]][i];
}
}
}
int query(string s){
int ans=0,x=0;
int len=s.size();
for(int i=0;i<len;i++){
x=a[x][s[i]-'a'];
for(int j=x;j&&cnt[j]!=-1;j=fail[j]){
ans+=cnt[j];
cnt[j]=-1;
}
}
return ans;
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>sz;
insert(sz);
}
fail[0]=0;
getfail();
cin>>sz;
cout<<query(sz);
}
/*
5
she
he
say
shr
her
yasherhs
3
*/
分析过程时,最好弄个完全26叉树,根节点下再弄排根节点,看最下面的根节点的a数组,fail失溯指针不难理解。
加强版模板题:(洛谷P3796)
有 N 个由小写字母组成的模式串以及一个文本串 T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串 T 中出现的次数最多。
输出:第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。
我看见这题网上还有ac自动机和树状数组结合做的,时间复杂度更小 玄学题解
例题:题集
HDU - 2896 :记录哪些字符串出现和其出现次数。
POJ - 2778 :ac自动机+矩阵乘法的结合(待完善)