poj-3630 Phone List **
2011-10-06 17:39
337 查看
Trie树入门题。不多说了, 先转一个人家的分析和代码, 自己的代码附在后面。
[转]:
方法一:trie树
有了上面学习的思考与总结,3630用trie树本以为可以水过,可是学习和做题终究是两回事,我很快写出trie树,然后提交,超时了。
后来受discuss提示,我大致计算了一下本题trie树的复杂度,号码个数10000,长度10,树的宽度大概有10000,所以总的节点数大概就有100,000级(10层,每层10000),即要进行十万次new的操作,确实时间耗费很多,估计这样题目的用时要有1秒到2秒左右的样子。
于是为了纯粹的做题,我将new操作省掉,改为提前申请一个buffer空间,就ac了,时间变为125ms了,不过这样确实挺耗空间的,没办法,为了做题只能用空间换时间。
代码如下:
方法二:
转成数字存储比较,这样的话用long整形就可以,然用除法+取余的方法核对是否是某个数字的前缀,但是这种方法的复杂度显然是O(n^2)呀,所以就不尝试了。
方法三:
受大雄提示,可以使用字符串排序比较来做,因为通过排序,前缀子串肯定是与父串挨着的,嘿嘿,这样做,思路简单、代码量少,易理解啊,所以很快ac,下面分析一下复杂度。
理论上使用trie的平均复杂度应该是n*len;其中,len是号码的平均长度,n是号码的个数。使用数组进行字符比较,理论上的复杂度有n*len+logn,排序为logn,然后查询是否存在前缀子串是n*len。所以后者应该时间稍微多一点,提交后果然,耗时188ms。
另外值得一提的是使用数组比较的方法有个好处,那就是地址都是连续的,cpu在寻址时会非常快,而用链式结构(即指针),包括使用数组型的trie树则是跳来跳去的,故会有一些开销吧。
呵呵,我所崇拜的排序又一次派上用场了。
代码如下:
[转] : http://www.cnblogs.com/cherish_yimi/archive/2009/10/12/1581795.html
__________________________________________________________________________________________
MyCode :
Input:
[转]:
方法一:trie树
有了上面学习的思考与总结,3630用trie树本以为可以水过,可是学习和做题终究是两回事,我很快写出trie树,然后提交,超时了。
后来受discuss提示,我大致计算了一下本题trie树的复杂度,号码个数10000,长度10,树的宽度大概有10000,所以总的节点数大概就有100,000级(10层,每层10000),即要进行十万次new的操作,确实时间耗费很多,估计这样题目的用时要有1秒到2秒左右的样子。
于是为了纯粹的做题,我将new操作省掉,改为提前申请一个buffer空间,就ac了,时间变为125ms了,不过这样确实挺耗空间的,没办法,为了做题只能用空间换时间。
代码如下:
1#include<iostream> 2using namespace std; 3int cases, count; 4int nodenum; 5 6struct node 7{ 8 bool isExist; 9 node * branch[10]; 10}Node[100000]; 11 12class Trie 13{ 14private: 15 node root; 16public: 17 Trie(){root = Node[0];} 18 bool insert(char num[]) 19 { 20 node *location = &root; 21 int i = 0; 22 int len = strlen(num); 23 while(num[i]) 24 { 25 if(i==len-1 && location->branch[num[i]-'0'] != NULL) //解决没有按照长度排序而存在的问题 26 { 27 return false; 28 } 29 if(location->branch[num[i]-'0']==NULL)//没有建立 30 { 31 location->branch[num[i]-'0'] = &Node[nodenum]; 32 Node[nodenum].isExist = false; 33 memset(Node[nodenum].branch,NULL,sizeof(Node[nodenum].branch)); 34 nodenum++; 35 } 36 if(location->branch[num[i]-'0']->isExist == true) 37 { 38 return false; 39 } 40 location = location->branch[num[i]-'0']; 41 i++; 42 } 43 location->isExist = true; 44 return true; 45 } 46}; 47 48int main() 49{ 50 scanf("%d",&cases); 51 while(cases--) 52 { 53 nodenum = 1; 54 bool flag = true; 55 scanf("%d",&count); 56 char tel[11]; 57 Trie t; 58 while(count--) 59 { 60 scanf("%s",tel); 61 if(!t.insert(tel)) 62 { 63 flag = false; 64 } 65 } 66 if(flag) 67 { 68 printf("YES\n"); 69 } 70 else 71 { 72 printf("NO\n"); 73 } 74 } 75 return 0; 76} 77
方法二:
转成数字存储比较,这样的话用long整形就可以,然用除法+取余的方法核对是否是某个数字的前缀,但是这种方法的复杂度显然是O(n^2)呀,所以就不尝试了。
方法三:
受大雄提示,可以使用字符串排序比较来做,因为通过排序,前缀子串肯定是与父串挨着的,嘿嘿,这样做,思路简单、代码量少,易理解啊,所以很快ac,下面分析一下复杂度。
理论上使用trie的平均复杂度应该是n*len;其中,len是号码的平均长度,n是号码的个数。使用数组进行字符比较,理论上的复杂度有n*len+logn,排序为logn,然后查询是否存在前缀子串是n*len。所以后者应该时间稍微多一点,提交后果然,耗时188ms。
另外值得一提的是使用数组比较的方法有个好处,那就是地址都是连续的,cpu在寻址时会非常快,而用链式结构(即指针),包括使用数组型的trie树则是跳来跳去的,故会有一些开销吧。
呵呵,我所崇拜的排序又一次派上用场了。
代码如下:
1#include<iostream> 2using namespace std; 3 4int cases, count; 5char tel[10005][11]; 6int i, j; 7 8int cmp(const void *a, const void *b) 9{ 10 return strcmp( (char*)a,(char*)b ); 11} 12 13int main() 14{ 15 scanf("%d",&cases); 16 while(cases--) 17 { 18 bool flag = true; 19 scanf("%d",&count); 20 for(i = 0; i < count; i++) 21 { 22 scanf("%s",tel[i]); 23 } 24 qsort(tel,count,sizeof(char)*11,cmp); 25 int len1, len2; 26 for(i = 1; i < count; i++) 27 { 28 len1 = strlen(tel[i-1]); 29 len2 = strlen(tel[i]); 30 j = 0; 31 if(len1 <= len2) 32 { 33 while(tel[i-1][j] == tel[i][j] && j < len1) 34 { 35 j++; 36 } 37 if(j == len1) 38 { 39 flag = false; 40 } 41 } 42 if(!flag) 43 { 44 break; 45 } 46 } 47 if(flag) 48 { 49 printf("YES\n"); 50 } 51 else 52 { 53 printf("NO\n"); 54 } 55 } 56 return 0; 57} 58
[转] : http://www.cnblogs.com/cherish_yimi/archive/2009/10/12/1581795.html
__________________________________________________________________________________________
MyCode :
/* * test-3.cpp * * Created on: 2011-10-6 * */ #include <cstdio> #include <cstring> using namespace std; const int maxN = 10000 + 5; const int maxL = 10 + 3; const int alphbetNum = 10; int caseNum, n, nodeNum; char telNum[maxL]; struct SData{ SData *next[alphbetNum]; int isExist; }; SData trieTree[100000]; SData *trie; SData* createTrie(){ SData *tmpTrie = &trieTree[0]; for(int i=0; i<alphbetNum; i++) tmpTrie->next[i] = NULL; tmpTrie->isExist = 0; return tmpTrie; } int insert(char *newString){ SData *tmpTrie = trie; char *nextChar = newString; while(*nextChar != '\0'){ if(tmpTrie->isExist == 1) return -1; //关于这一步可以用负在下面的测试数据说明 if(strlen(nextChar) == 1 && tmpTrie->next[*nextChar - '0'] != NULL) return -1; if(tmpTrie->next[*nextChar - '0'] != NULL) tmpTrie = tmpTrie->next[*nextChar - '0']; else{ tmpTrie->next[*nextChar - '0'] = &trieTree[++nodeNum]; tmpTrie = tmpTrie->next[*nextChar - '0']; for(int j=0; j<alphbetNum; j++) tmpTrie->next[j] = NULL; tmpTrie->isExist = 0; } nextChar++; } tmpTrie->isExist = 1; return 1; } int main(){ scanf("%d", &caseNum); while(caseNum--){ nodeNum = 0; trie = createTrie(); bool flag = 1; scanf("%d", &n); for(int i=0; i<n; i++){ scanf("%s", telNum); //如果flag=0则后面的不用再插入了 if(flag && insert(telNum) == -1) flag = 0; } if(!flag) printf("NO\n"); else printf("YES\n"); } return 0; }
Input:
2 2 1 12 2 12 1 Output: NO NO
相关文章推荐
- POJ 3630 Phone List
- HDU 1671 POJ 3630 Phone List
- poj 3630 Phone List
- poj 3630 Phone List(Trie)
- POJ 3630-Phone List【比较许多字符中有没有一个是另一个的前缀,简单方法】
- POJ 3630 Phone List(Trie树,静态数组实现)
- 【原】 POJ 3630 Phone List Trie树 解题报告
- POJ 3630 Phone List 已被翻译
- POJ 3630 Phone List
- poj 3630(phone list)
- poj 3630 Phone List 贪心
- POJ 3630 Phone List
- POJ 3630 Phone List
- POJ3630 Phone List 题解&代码
- poj 3630 Phone List trie
- poj 3630 Phone List (字典树 +静态字典树)
- POJ 3630 Phone List
- POJ-3630 Phone List 字典树
- poj - 3630 - Phone List
- poj 3630 Phone List (字典树)