統計難題
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
字典樹,經典題。
今早看了看資料,晚上就會做題了,真的不難,不明白自己為什么放了這么久才看。字典樹還是很簡單的。
我用了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