hdu 1251:統計難題(字典樹,經典題)


統計難題

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)
Total Submission(s): 16905    Accepted Submission(s): 7273


Problem Description
Ignatius最近遇到一個難題,老師交給他很多單詞(只有小寫字母組成,不會有重復的單詞出現),現在老師要他統計出以某個字符串為前綴的單詞數量(單詞本身也是自己的前綴).
 

 

Input
輸入數據的第一部分是一張單詞表,每行一個單詞,單詞的長度不超過10,它們代表的是老師交給Ignatius統計的單詞,一個空行代表單詞表的結束.第二部分是一連串的提問,每行一個提問,每個提問都是一個字符串.

注意:本題只有一組測試數據,處理到文件結束.
 

 

Output
對於每個提問,給出以該字符串為前綴的單詞的數量.
 

 

Sample Input
banana
band
bee
absolute
acm
 
ba
b
band
abc
 

 

Sample Output
2
3
1
0
 

 

Author
Ignatius.L
 

 

Recommend
Ignatius.L   |   We have carefully selected several similar problems for you:   1075  1247  1671  1298  1800 

 
  字典樹,經典題
  今早看了看資料,晚上就會做題了,真的不難,不明白自己為什么放了這么久才看。字典樹還是很簡單的。
  我用了2種做法給大家參考,一種是用鏈表存儲,一種是用數組存儲。
  思路
    字典樹的經典應用,給你多個單詞,構建字典樹,然后給你一個字符串,求以這個字符串為前綴的單詞的數量。
  注意
    注意如何判斷空行,我用了2種方法。
    1、用strlen()計算字符串的長度,如果長度為0,說明為空行,退出輸入循環。見代碼一
    2、用gets()讀入。讀入的回車符會自動轉換為NULL。所以循環讀入,每次檢測讀入進來的字符串的第一個字符是否為NULL即可。見代碼二。
  代碼一(鏈表)
 1 #include <iostream>
 2 #include <string.h>
 3 using namespace std;  4 
 5 struct Trie{    //字典樹定義
 6     Trie* next[26];  7     int num;    //以當前字符串為前綴的單詞的數量
 8     Trie()    //構造函數
 9  { 10         int i; 11         for(i=0;i<26;i++){ 12             next[i] = NULL; 13  } 14         num=0; 15  } 16 }; 17 Trie root; 18 void Insert(char word[])    //將字符串word插入到字典樹中
19 { 20     Trie *p = &root; 21     int i; 22     for(i=0;word[i];i++){    //遍歷word的每一個字符
23         if(p->next[word[i]-'a']==NULL)    //如果該字符沒有對應的節點
24             p->next[word[i]-'a'] = new Trie;    //創建一個
25         p = p->next[word[i]-'a']; 26         p->num++; 27  } 28 } 29 int Find(char word[])    //返回以字符串word為前綴的單詞的數量
30 { 31     Trie *p = &root; 32     int i; 33     for(i=0;word[i];i++){    //在字典樹找到該單詞的結尾位置
34         if(p->next[word[i]-'a']==NULL) 35             return 0; 36         p = p->next[word[i]-'a']; 37  } 38     return p->num; 39 } 40 
41 int main() 42 { 43     char word[11]; 44     while(cin.getline(word,12)){    //輸入單詞
45         if(strlen(word)==0 || word[0]==' ')    //如果讀入字符串的長度為0或者是空格,說明讀入的是空行
46             break; 47  Insert(word); 48  } 49     while(scanf("%s",word)!=EOF){ 50         printf("%d\n",Find(word));    //返回word為前綴的單詞的數量
51  } 52     return 0; 53 }

   代碼二(數組)

 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;  4 
 5 int trie[1000010][26];    //數組形式定義字典樹,值存儲的是下一個字符的位置
 6 int num[1000010]={0};    //附加值,以某一字符串為前綴的單詞的數量
 7 int pos = 1;  8 
 9 void Insert(char word[])    //在字典樹中插入某個單詞
10 { 11     int i; 12     int c = 0; 13     for(i=0;word[i];i++){ 14         int n = word[i]-'a'; 15         if(trie[c][n]==0)    //如果對應字符還沒有值
16             trie[c][n] = pos++; 17         c = trie[c][n]; 18         num[c]++; 19  } 20 } 21 int Find(char word[])    //返回以某個字符串為前綴的單詞的數量
22 { 23     int i; 24     int c = 0; 25     for(i=0;word[i];i++){ 26         int n = word[i]-'a'; 27         if(trie[c][n]==0) 28             return 0; 29         c = trie[c][n]; 30  } 31     return num[c]; 32 } 33 
34 int main() 35 { 36     char word[11]; 37     while(gets(word)){ 38         if(word[0]==NULL)    //空行。gets讀入的回車符會自動轉換為NULL。
39             break; 40  Insert(word); 41  } 42     while(gets(word)) 43         printf("%d\n",Find(word)); 44     return 0; 45 }

SUM

  以下是2種做法的效率對比

  第二行的是第一種做法,第一行的是第二種做法,很明顯,數組做法不管是在時間,空間,代碼量上都要優於鏈表做法。

  但是數組的不太好理解,如何取舍看各位看官的意思吧。

 

Freecode : www.cnblogs.com/yym2013


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM