• 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




  • 相关阅读:
    HtmlEncode 和 HtmlDecode
    Visual Studio .Net 的一些小技巧(2)
    Array和ArrayList的区别
    c#中 ?? 是什么意思?
    带有图片预览功能的上传表单 上传预览
    Js实现Repeater全选/反选 功能 终极解决方案
    处理URL重写后postback重写失效的问题 .browser文件
    在TreeView中使用CheckBox(c#)
    SQL操作全集
    智能仓库管理系统方案(一)
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2200034.html
Copyright © 2020-2023  润新知