基础知识
我感觉自己总结的不太好,推荐大佬的博客和视频,配合食用效果更好。
博客链接: link.
视频链接: link.
模板
#include <iostream>
#include <string.h>
#include <cstdio>
#include <cstdlib>
using namespace std;
int Tree[100010][26];
//tree[pos][k]:编号为pos的点走到编号为tree[pos][k]的点所需要k的路程
bool flag[100010]//用来记录标记结点
int cnt;//cnt记录当前这棵树有多少个结点
//插入
void Insert(char *str)
{
int len = strlen(str);
int pos = 0;
int k;
for(int i=0; i<len; i++)
{
k = str[i]-'a';
if(!tree[pos][k])
tree[pos][k] = ++cnt;
pos = tree[pos][k];
}
flag[pos] = 1;
}
//查找
inline bool Search1(char *str)//查询是否存在这个字符串
{
int pos = 0;
int k;
int len = strlen(str);
for(int i=0; i<len; i++)
{
k = str[i]-'a';
if(!tree[pos][k])//没有这条边,所以不存在这个字符串
return 0;
pos = tree[pos][k];
}
return flag[pos];//是否有字符串在pos点结束
}
inline bool Search2(char *str)//查询是否有这个字符串的前驱字符串
{
int k;
int pos = 0;
int len = strlen(str);
for(int i=0;i<len;i++)
{
k = str[i]-'a';
if(flag[pos])
return 1;//如果有点在遍历字符串str的路径上且这个点是标记点,那么已经遍历到的字符串就是这个字符串的前驱
if(!tree[pos][k])
return 0;//没有这条边,而且之前没有找到前驱字符串,自然没有这个字符串的前驱字符串
pos = tree[pos][k];
}
return flag[pos];//相同也算作前驱字符串
}
//删除
inline void Delete(char *str)
{
int k;
int pos = 0;
int len = strlen(str);
for(int i=0;i<len;i++)
{
k = str[i]-'a';
if(!tree[pos][k])
return ;//都没有这个字符串,返回
pos = tree[pos][k];
}
if(!flag[pos])
return ;//都没有这个字符串,删除空气并返回
flag[pos] = 0;//删除字符串的末尾
for(int i=0;i<26;i++)
{
if(tree[pos][i])
return ;//后面还有其他的字符串,也要遍历到这里,不能删除其他边
}
for(int i=l;i<len;i++)
tree[pos][s[i]-'a'] = 0;//删除最近的没有分叉的,也就是只有一条链下到点pos,要删除这些边
}
例题
链接: link.
这道题是个标准的模板题,直接上代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string.h>
using namespace std;
const int N = 2e6+5;
int tree[N][15];
bool flag[N];
int cnt;
char str[10010][12];
//字典树模板
void Insert(char *ch)
{
int k;
int pos = 0;
int len = strlen(ch);
for(int i=0;i<len;i++)
{
k = ch[i]-'0';
if(!tree[pos][k])
tree[pos][k] = ++cnt;
pos = tree[pos][k];
}
flag[pos] = true;
}
int Find(char *ch)
{
int k;
int pos = 0;
int len = strlen(ch);
for(int i=0;i<len-1;i++)//这里注意是len-1,因为不能包括自身
{
k = ch[i]-'0';
if(flag[pos])
return true;
if(!tree[pos][k])
return false;
pos = tree[pos][k];
}
return flag[pos];
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",str[i]);
Insert(str[i]);
}
int Flag = 0;
for(int i=0;i<n;i++)
{
if(Find(str[i]))
{
Flag = 1;
break;
}
}
if(Flag==0)
printf("YES\n");
else
printf("NO\n");
for(int i=0;i<=cnt;i++)//用memset进行初始化会超出内存限制
{
flag[i] = false;
for(int j=0;j<10;j++)
tree[i][j] = 0;
}
cnt = 0;
}
return 0;
}