Phone List
题目描述
题目来源:题目
给定 n 个长度不超过 10 的数字串,问其中是否存在两个数字串 S、T,使得 S是 T 的前缀,多组数据。
输入格式
第一行一个整数 T,表示数据组数。
对于每组数据,第一行一个数 n,接下来 n 行输入 n 个数字串。
输出格式
对于每组数据,若存在两个数字串 S,T,使得 S 是 T 的前缀,则输出 NO ,否则输出 YES 。
请注意此处结果与输出的对应关系!
样例输入
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
样例输出
NO
YES
数据范围与提示
对于 100% 的数据 1<=T<=40,1<=n<=10^4。
题解:将所有字符串构建一棵Trie树,在构建的过程中就可以判断。
1、若当前字符串插入后没有新建任何结点并且该字符串插入完毕,则当前串肯定是之前插入的某个串的前缀。
2、若插入过程中,某个结点经过某个串结尾标记的结点,则该某个串是当前串的前缀。
依据这两种情况判断结果。
AC代码:
#include<stdio.h>
#include<string.h>
const int N=1e5+5;
const int Z=10;
int T,n,tot;
int ch[N][Z];
bool bo[N];
char s[20];//给出长度不超过10的字符串,所以我们s数组开成20
void clear()
{
memset(ch,0,sizeof(ch));
memset(bo,false,sizeof(bo));
}
bool insert(char *s)
{
int len=strlen(s);
//每次u都要从1开始,因为我们新插入一个单词的时候都要从第一个来判断有没有这个单词,
//即找到已有的这一列,如果没有这一列就要新建立一列
int u=1;//1为根节点 ,u是用来记录位置的
bool flag=false;
for(int i=0; i<len; i++)
{
int c=s[i]-'0';
if(!ch[u][c])//
ch[u][c]=++tot;//创建一个新节点
else if(i==len-1)//ch[u][c]为真&&i==len-1
flag=true;//没有插入任何新结点
u=ch[u][c];//令u等于当前节点所指向的节点
//如果当前节点所指向的节点位置是一个单词的尾部
if(bo[u])//经过有标记的结点
flag=true;
}
//for循环结束,u就为最后一个单词所指向的结点
bo[u]=true;//把该单词的尾部标记为真
return flag;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
tot=1;//tot为总点数
clear();
bool ans=false;
for(int i=1; i<=n; i++)
{
scanf("%s",s);
if(insert(s))
ans=true;
}
if(!ans)
puts("YES");
else
puts("NO");
}
return 0;
}