zoukankan      html  css  js  c++  java
  • poj3630 Phone List **

      Trie树入门题。不多说了, 先转一个人家的分析和代码, 自己的代码附在后面。

    [转]:

    方法一:trie

    有了上面学习的思考与总结,3630trie树本以为可以水过,可是学习和做题终究是两回事,我很快写出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




  • 相关阅读:
    linux sysfs (2)
    微软——助您启动云的力量网络虚拟盛会
    Windows Azure入门教学系列 全面更新啦!
    与Advanced Telemetry创始人兼 CTO, Tom Naylor的访谈
    Windows Azure AppFabric概述
    Windows Azure Extra Small Instances Public Beta版本发布
    DataMarket 一月内容更新
    和Steve, Wade 一起学习如何使用Windows Azure Startup Tasks
    现实世界的Windows Azure:与eCraft的 Nicklas Andersson(CTO),Peter Löfgren(项目经理)以及Jörgen Westerling(CCO)的访谈
    正确使用Windows Azure 中的VM Role
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2200034.html
Copyright © 2011-2022 走看看