HDU 1671 Phone List
- 题意:多组输入。输入n个电话号码。判断有没有电话号码是其他电话号码的前缀。如样例1。
思路
将所有号码建立一颗Trie树,开sum[]数组记录前缀出现的次数。然后再遍历每一个号码串看它是不是前缀出现次数为1. 如果是说明合法~
Trie树的时间复杂度
插入:O(len). len是插入的串的长度。这里不超过10,那就是O(1)咯,常数级别的
建树【=插入所有串总时间复杂度】:O(n*len). n是串的个数,len是串的长度。这道题开空间就要开n*len = 10000 * 10,当然再大点儿开够~ 100000 + 7(喜欢7~)
查询:O(len). len是查询的串的长度。一样,长度不超过10,所以还是O(1),常数级别
查询所有串的总时间复杂度:O(n*len).
- 所以这份代码的时间复杂度就是O(n*len) = O(100000)
注意
- 这里我用了开辟一个新的编号才初始化 tire[tot] 的方式,快啊~但是因为是多组输入,所以一定记得每组都要初始化根结点0:Clear(0)。吃了这个亏啊TAT
- 而且tot没初始化还报了RE。
- 还有就是puts()是带着回车一起输出的,所以不用再单独输出回车了!【话说每次关于字符串的输入输出都搞得头大!】
嗐!
AC CODE
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 100000 + 7;
char ans[2][10];
int tire[maxN][10], sum[maxN], tot;
void init()
{
strcpy(ans[0], "NO");
strcpy(ans[1], "YES");
}
void Clear(int rt)
{
for(int i = 0; i < 10; i ++ )
tire[rt][i] = 0;
sum[rt] = 0;
}
void Insert(char *s)
{
int len = strlen(s);
int rt = 0;
for(int i = 0; i < len; i ++ )
{
int id = s[i] - '0';
if(!tire[rt][id]) { tire[rt][id] = ++tot; Clear(tot); }
++ sum[tire[rt][id]];
rt = tire[rt][id];
}
}
bool Search(char *s)
{
int len = strlen(s);
int rt = 0;
for(int i = 0; i < len; i ++ )
{
int id = s[i] - '0';
rt = tire[rt][id];
}
return sum[rt] == 1;
}
int n;
char s[10007][15];
int main()
{
init();
int TAT; scanf("%d", &TAT);
while(TAT -- )
{
tot = 0; Clear(0);
scanf("%d", &n);
for(int i = 0; i < n; i ++ )
{
scanf("%s", s[i]);
Insert(s[i]);
}
int p = 1;
for(int i = 0; i < n; i ++ )
{
if(!Search(s[i]))
{
p = 0;
break;
}
}
puts(ans[p]);
}
return 0;
}