构建字典图实现自动跳转,构建失配指针实现多模式匹配
(fail)指针表示文本串在当前节点失配后,我们应该到哪个节点去继续匹配,(u)的(fail)指针指向(v)表示从根到(v)的字符串为从根到(u)的字符串的最长后缀,用(bfs)来构建(fail)指针
(fail[trie[x][i]]=trie[fail[x]][i])
相当于在(x)和(fail[x])后面加一个字符(i),就构成(fail[trie[x][i]])
若发现(trie[x][i])不存在,则直接将其(trie[fail[x]][i])赋值给它,来实现一个类似于路径压缩的操作
(code):
void insert(char *str)
{
int len=strlen(str+1),p=root;
for(int i=1;i<=len;++i)
{
int ch=str[i]-'a';
if(!trie[p][ch]) trie[p][ch]=++tot;
p=trie[p][ch];
}
num[p]++;
}
void build()
{
queue<int> q;
for(int i=0;i<26;++i)
if(trie[root][i])
q.push(trie[root][i]);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<26;++i)
{
int y=trie[x][i];
if(y) fail[y]=trie[fail[x]][i],q.push(y);
else trie[x][i]=trie[fail[x]][i];
}
}
}
int query(char *str)
{
int len=strlen(str+1),p=root,ans=0;
for(int i=1;i<=len;++i)
{
int ch=str[i]-'a';
p=trie[p][ch];
for(int j=p;j&&num[j]!=-1;j=fail[j])
ans+=num[j],num[j]=-1;
}
return ans;
}