统计难题 (字典树,val值统计经过该点的字母数量)
扫描二维码
随时随地手机看文章
题面:
统计难题
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)
Total Submission(s): 25921 Accepted Submission(s): 10560
Problem Description
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.
注意:本题只有一组测试数据,处理到文件结束.
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana
band
bee
absolute
acm
ba
b
band
abc
Sample Output
2
3
1
0
题意:
额,中文大家都懂。
解题:
字典树裸题,val值统计经过该点的字母数量。
代码:
#include#include#include#includeusing namespace std; struct Trie { //用来储存该节点的26个字母下标,ch的第一维要注意,要开大,不然会T int ch[1000010][26]; //val数组一般用来存储权值,视题目灵活运用,sz是当前节点数量 int val[1000010],sz; //初始化 void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); } //插入一条单词 void insert(string s) { //u是节点编号,并不是层数 int u=0,len=s.length(); for(int i=0;i<len;i++) { //取下标 int c=(s[i]-'a'); //如果该节点不存在,创建该节点 if(!ch[u][c]) { //真的是相当的省 memset(ch[sz],0,sizeof(ch[sz])); //因为刚创建所以为1 val[sz]=1; //给该节点分配编号 ch[u][c]=sz++; //下移 u=ch[u][c]; } //已经存在了 else { //下移,并计数值加一 u=ch[u][c]; val[u]++; } } } //查询前缀 int query(string s) { int len=s.length(),u=0,c; //不断下移,直至移到给定的前缀的最后一个单词 bool sign=true; for(int i=0;i<len;i++) { c=s[i]-'a'; if(ch[u][c]) u=ch[u][c]; else { sign=false; break; } } if(sign) return val[u]; else return 0; } }; Trie T; int main() { string s; T.init(); while(getline(cin,s)) { if(s=="")break; T.insert(s); } while(getline(cin,s)) { cout<<T.query(s)<<endl; } return 0; }