统计难题
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)Total Submission(s): 12660 Accepted Submission(s): 5352
Problem Description
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.
注意:本题只有一组测试数据,处理到文件结束.
注意:本题只有一组测试数据,处理到文件结束.
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana band bee absolute acm ba b band abc
Sample Output
2 3 1 0字典树的基本功能是用来查询某个单词(前缀)在所有单词中出现次数的一种数据结构,它的插入和查询复杂度都为O(len),Len为单词(前缀)长度,但是它的空间复杂度却非常高,如果字符集是26个字母,那每个节点的度就有26个,典型的以空间换时间结构。这题就是统计一组字符串中某前缀出现次数(字典树第一类应用),因此只要简单的套模板就行了(在节点中设置一个成员变量nCount,来记录该字符出现次数)AC代码:#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cmath> #include <string> #define maxn 26 using namespace std; typedef struct TireNode { int nCount; //记录该字符出现次数 struct TireNode *next[maxn]; }TireNode; TireNode Memory[1000000]; int allocp=0; /*初始化*/ void InitTireRoot(TireNode **pRoot) { *pRoot=NULL; } /*创建新结点*/ TireNode *CreatTireNode() { TireNode *p; p=&Memory[allocp++]; p->nCount=1; for(int i=0;i<maxn;i++) p->next[i]=NULL; return p; } /*插入*/ void InsertTire(TireNode **pRoot,char *s) { int i=0,k; TireNode *p; if(!(p=*pRoot)) p=*pRoot=CreatTireNode(); while(s[i]) { k=s[i++]-'a'; //确定branch if(p->next[k]) p->next[k]->nCount++; else p->next[k]=CreatTireNode(); p=p->next[k]; } } //查找 int SearchTire(TireNode **pRoot,char *s) { TireNode *p; int i=0,k; if(!(p=*pRoot)) return 0; while(s[i]) { k=s[i++]-'a'; if(p->next[k]==NULL) return 0; p=p->next[k]; } return p->nCount; } int main() { char s[11]; TireNode *Root=NULL; InitTireRoot(&Root); while(gets(s)&&s[0]) InsertTire(&Root,s); while(gets(s)) printf("%d\n",SearchTire(&Root,s)); return 0; }