题意:给你N个电话号码最为一组,如果这一组中有一个电话号码是另外一个电话号码的前缀,此时该组电话号码不能共存,输出“NO”;否则输出“YES”。
解题思路:先将每组电话号码建立成一棵字典树,然后在再利用字典树来查询这一组电话号码,如果查询到某个电话号码的最后为数字后面的子节点大于2,则说明该组电话号码存在某个电话号码是另外一个电话号码的前缀,故输出“NO”,若返回值全部为1,则输出“YES”,详见代码。注意:看此代码前应先熟悉字典树的建立和查询规则。
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct Trie
{
Trie *next[10];
int v;
};
Trie *root;
Trie *newnode()
{
Trie *t;
t = new Trie;
for(int i = 0; i < 10; i++)
t->next[i] = NULL;
return t;
}
void CreatTrie(char *str)
{
int len = strlen(str);
Trie *q,*p = root;
for(int i = 0; i < len; i++)
{
int id = str[i] - '0';
if(p->next[id] == NULL)
{
q = newnode();
q->v = 1;
p->next[id] = q;
p = p->next[id];
}
else
{
p->next[id]->v++;
p = p->next[id];
}
}
}
int search(char *str)
{
int len = strlen(str);
Trie *p = root;
for(int i = 0; i<len; i++)
{
int id = str[i]-'0';
p = p->next[id];
if(p == NULL) return 0;
}
return p->v;
}
int dealTrie(Trie *T)
{
if(T == NULL) return 0;
for(int i = 0; i<10; i++)
{
if(T->next[i] != NULL) dealTrie(T->next[i]);//递归调用,来消除每个节点
}
delete(T);
return 0;
}
int main()
{
//freopen("input.txt","r",stdin);
int t,n;
char array[10005][15];
scanf("%d",&t);
while(t--)
{
root = newnode();
scanf("%d",&n);
for(int i = 0; i<n; i++)
{
scanf("%s",&array[i]);
CreatTrie(array[i]);//先将每个电话号建立成一个字典树
}
int flag = 1;
for(int j = 0; j<n; j++)
{
int temp = search(array[j]);
if(temp > 1) { flag = 0; break;}//然后再次查询每个电话号,如果查到某个电话号的最后一个结点v值大于1,则说明此电话号可作为另外一个电话号的前缀,不符合条件,直接跳出
}
if(flag) printf("YES\n");
else printf("NO\n");
dealTrie(root);//因为测试有很多组,所以在每次动态的建立字典树后,要进行消除,防止内存溢出
}
return 0;
}