题目链接:https://loj.ac/problem/10049
Trie字典树知识点:
操作实现:
初始化:一棵树空Trie仅包含一个根节点,该点的字符指针均指向空。
插入:当需要插入一个字符串S时,我们令一个指针P起初指向根节点。然后,依次扫描S中的每个字符c。
查询:当需要查询一个字符串S在Trie中是否存在时,我们令一个指针起初指向根节点,然后依次扫描S中的每个字符c。
特点:
字符数据都体现在树的边(指针)上,树的结点仅保存一些额外信息。例如,单词结尾标志。
代码实现:
ch[u][i]表示结点u的i字符指针指向的结点,若数组的值为0,则表示没有这个子结点。
int ch[N][Z]; //N为结点的个数,Z为字符集大小
bool bo[N]; //若bo=true则表示从根到该点经过的边上的字母组成的字符串是实际字符串集合中的元素
对一个字符集为小写英文字母的trie插入一个字符串S
void solve(char *s)
{
int len=strlen(s);
int u=1;/*1为根节点*/
for(int i=0;i<len;i++)
{
int c=s[i]-'a';
if(!ch[u][c])
ch[u][c]=++tot;/*若不存在这条边则新建一个结点与转移边*/
u=ch[u][c];/*tot为总点数*/
}
bo[u]=true;/*在串的结尾处将bo赋值,表示它代表一个实际字符串集合中的元素*/
}
查询一个字符串S是否是给定字符串集合中某个串的前缀
bool fin(char *s)
{
int len=strlen(s);
int u=1;
for(int i=0;i<len;i++)
{
int c=s[i]-'a';
if(!ch[u][c])
return false;
u=ch[u][c];
}
return true;
}
完整代码:
#include <cstdio>
#include <cstring>
const int N = 1e5 + 10;
int ch[N][20], n, lot;
char a[11];
bool book[N];
bool solve(char *a) {
int u = 1, len = strlen(a);
bool flag = false;
for (int i = 0; i < len; i++) {
int c = a[i] - '0';
if (!ch[u][c])
ch[u][c] = ++lot;
else if (i == len - 1)
flag = true;
u = ch[u][c];
if (book[u])
flag = true;
}
book[u] = true;
return flag;
}
void init() {
lot = 1;
memset(ch, 0, sizeof(ch));
memset(book, false, sizeof(book));
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
bool ans = false;
init();
while (n--) {
scanf("%s", a);
if (solve(a))
ans = true;
}
if (ans)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}