推荐博客:https://blog.csdn.net/liu940204/article/details/51347064
https://blog.csdn.net/silence401/article/details/52662605
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Node
{
int cnt;//是否为单词结尾
Node *fail;//失败指针
Node *next[26];
};
struct Node *queue[500005];//队列, BFS构造失败指针时使用
char s[1000005];//主串
char keyword[55];//单词
Node *root;//根节点
void Init(Node *tmp)//初始化结点函数
{
tmp->cnt = 0;
tmp->fail = NULL;
for(int i = 0; i <26; i++)
tmp->next[i] = NULL;
}
void Build_tire(char *word)// 构建trie函数 或者 插入单词函数
{
Node *tmp = root;
int ch;
int len = strlen(word);
for(int i =0; i < len; i++)
{
ch = word[i] - 'a';
if(tmp->next[ch] == NULL)//如果该节点所代表的字母 为空 就申请空间构建
{
tmp->next[ch] = (struct Node *)malloc(sizeof(Node));
Init(tmp->next[ch]);
}
tmp = tmp->next[ch];//移到ch所在结点
}
tmp->cnt++;// 单词结尾cnt++
}
void Build_fail_pointer(Node *root)// fail指针构建函数 本质是bfs实现
{
int head =0, tail = 0;//队首 队尾
queue[tail++] = root;//根节点入队
while(head != tail)
{
Node *tmp = NULL;
Node *tp = queue[head++];//弹出队首
for(int i = 0; i < 26; i++)
{
if(tp->next[i] != NULL)
{
if(tp == root)// 第一层 没有子后缀 所以指向root
{
tp->next[i]->fail = root;
}
else
{
tmp = tp->fail;
while(tmp!= NULL)
{
if(tmp->next[i]!= NULL)
{
tp->next[i]->fail = tmp->next[i];
break; //
}
else tmp =tmp->fail;// 缩短后缀
}
if(tmp == NULL)// 没找到就指向root
tp->next[i]->fail = root;
}
queue[tail++] = tp->next[i];//处理完了 将他压入队列 ,用于继续处理后面的节点
}
}
}
}
int query(Node *root)
{
int cnt = 0;
int ch;
int len = strlen(s);
Node *p = root;
for(int r = 0; r < len; r++)
{
ch = s[r]-'a';
while(p->next[ch]==NULL &&p!= root)// 如果接着上次p点 如果为空 回溯 缩短后缀(相当于l向右)
p= p->fail;
p= p->next[ch];
if(p == NULL)// 为空 表示 没有与该位置s[r] 后缀 相似的前缀
{
p = root;
continue;//直接进行下个
}
Node *tmp = p;//
while(tmp != root)// 回溯过程( 向当于l,聪明的跳)
{
if(tmp->cnt >= 0)
{
cnt+=tmp->cnt;
tmp->cnt=-1; // 表示访问过
}
else if(tmp->cnt == -1)break; // -1表示从这开始访问过了, 所以就直接结束 循环
tmp = tmp->fail;// 如果不等于-1 继续回溯(缩短后缀)查询
}
}
return cnt;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
root = (Node *)malloc(sizeof(Node));
Init(root);
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%s", keyword);
Build_tire(keyword);
}
Build_fail_pointer(root);
scanf("%s", s);
int res = query(root);
printf("%d\n", res);
}
return 0;
}