一、题意
给出一组单词,另给出一组单词用作查询,求解对于每个用于查询的单词,前一组中有多少个单词以其为前缀。
二、分析
根据题目很容易想到hash的方法,首先可以朴素的考虑将第一组中的所有单词的前缀利用map进行统计,查询时直接得到结果
所以很容易可以得到以下代码。
注意:输入时的空行代表第一行的结束,利用gets读入并根据字符串的长度是否为0来判断;
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <map> 5 using namespace std; 6 const int maxn = 15; 7 char word[maxn]; 8 map<string,int> M; 9 int main() 10 { 11 while(gets(word)) 12 { 13 if(strlen(word) == 0) 14 break; 15 int L = strlen(word); 16 for(int i=L;i>0;i--) 17 { 18 word[i] = '\0'; 19 M[word]++; 20 } 21 } 22 while(gets(word)) 23 printf("%d\n",M[word]); 24 return 0; 25 }
然而,有些题目会卡map的用法,需要找到更高效的算法,这里可以使用Trie树,也就是前缀树、字典树来解决问题。
字典树的根节点为空,用边来表示字母,用根节点到某个节点的路径表示一个单词,字典树可以用数组表示,其中Tree[root][i]=k表示树上位置标号为root的节点的第i个子节点的位置编号为k
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 const int maxn = 2e6+5; 6 int Tree[maxn][30],sum[maxn]; 7 int cnt; 8 void Insert(char word[]) 9 { 10 int L = strlen(word); 11 int root = 0; 12 for(int i=0;i<L;i++) 13 { 14 int id = word[i] - 'a'; 15 if(!Tree[root][id]) 16 Tree[root][id] = ++cnt; 17 sum[Tree[root][id]]++; 18 root = Tree[root][id]; 19 } 20 } 21 int Find(char word[]) 22 { 23 int L = strlen(word); 24 int root = 0; 25 for(int i=0;i<L;i++) 26 { 27 int id = word[i] - 'a'; 28 if(!Tree[root][id]) 29 return 0; 30 root = Tree[root][id]; 31 } 32 return sum[root]; 33 } 34 int main() 35 { 36 char word[15]; 37 cnt = 0; 38 while(gets(word)) 39 { 40 if(strlen(word) == 0) 41 break; 42 Insert(word); 43 } 44 while(scanf("%s",word)!=EOF) 45 printf("%d\n",Find(word)); 46 return 0; 47 }
注意,如果第二组单词用scan读入记得写!=EOF的形式