题目大意:
给出几组电话号码,在某一组号码中,如果存在某一号码为其他号码的前缀,则输出NO,否则输出YES。
解题思路:
方法一:对每组中的电话号码进行排序,然后再从最短的电话开始与后面的电话号码进行比较,判断当前的电话号码是否是其他某些号码的前缀,直到该组结尾。当问题的规模较大时,这种方法的时间复杂度相对较高,然而空间复杂度则较低。
方法二:采用字典树实现对每组号码的存储,再逐一对组中的号码进行判断。这种方法空间复杂度较高,但是时间复杂度则很低。
另外如果每次插入号码时都new一个新的字典树结点,程序提交的结果是TLE。因此建立静态结点缓存,每次从缓存中取结点,插入字典树中。
具体实现代码如下:
#include <cstdio>
struct Trie
{
int count;
struct Trie *branch[10];
}Memory[10000]; //建立10000个静态结点
int num = 0;
Trie *TrieNode()
{
Trie *p = &Memory[num++];
p->count = 0;
for(int k = 0; k < 10; k++)
{
p->branch[k] = NULL;
}
return p;
}
//将字符串number插入根为root的字典树
void MakeTrie(Trie *&root, char *number)
{
int i = 0;
if(root == NULL)
{
root = TrieNode();
}
Trie *p = root;
while(number[i])
{
if(!p->branch[number[i] - '0'])
{
p->branch[number[i] - '0'] = TrieNode();
}
p = p->branch[number[i] - '0'];
p->count++;
i++;
}
}
//判断字符串number是否为其他某字符串的前缀
//如果是返回true,否则返回false
bool IsPrefix(Trie *root, char *number)
{
int i = 0;
if(root == NULL)
{
return true;
}
Trie *p = root;
while(number[i])
{
p = p->branch[number[i] - '0'];
if(p->count == 1)
return false;
i++;
}
return true;
}
int main()
{
bool flag = true;
int j, n, t;
Trie *root = NULL;
char numbers[10000][11];
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
root = NULL;
for(j = 0; j < n; j++)
{
scanf("%s", numbers[j]);
MakeTrie(root, numbers[j]);
}
for(j = 0; j < n; j++)
{
if(IsPrefix(root, numbers[j]))
{
flag = false;
break;
}
}
if(flag)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
flag = true;
num = 0;
}
return 0;
}