统计难题
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)
Total Submission(s): 69742 Accepted Submission(s): 24131
Problem Description
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.
注意:本题只有一组测试数据,处理到文件结束.
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana
band
bee
absolute
acm
ba
b
band
abc
Sample Output
2
3
1
0
-
题意:
统计后一组中每个字符串在前一组中出现的次数,并输出。 -
思路:
字符串匹配问题,可以用map,字典树,字典树又可以用指针和数组来实现,但是这个题用指针字典树会空间超额。想看更详细的思路,就点开这个神奇的链接吧。
题解(一位大佬的)把二维表格打出来了
下面来看详细代码:map实现
#include<bits/stdc++.h>
using namespace std;
int main(){
char str[10];
map<string,int>m;
while(gets(str)){
int len = strlen(str);
if(!len) break; //输入了一个空行
for(int i=len; i>0; i--){
str[i] = '\0';//从后往前删除这个字符串,得到前缀
m[str]++; //统计前缀的数量
}
}
while(gets(str))
cout<<m[str]<<endl;
return 0;
}
数组实现
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1e6 +10;
int trie[N][26]; //字典树数组,很巧妙地储存
/*
这个二维数组,在每一行中存的元素,都是在同一个深度上的根,从而可以达到分支的目的
每一列中的元素,则是代表每棵树的深度
这样行和列组合起来,就可一很好的确定树的分支了
自己课一用 for 循环 把数组打印出来看一下
思路中的第二个链接打印出的数组,可以看一下
*/
int num[N] = {0}; //统计每个字符串出现的个数
int pos =1;
char str[N]; //输入存样例用的
void Insert(char str[]){ //插入建树
int p = 0; //先从零行开始
for(int i=0; str[i]; i++){ //一直遍历到最后
int n= str[i] - 'a'; //转换成 int 存到数组当中
if(trie[p][n] == 0) //判断是否存入数组中
trie[p][n] = pos++; //pos 记录存的字符是第几个
p = trie[p][n]; //并且配和p来换行
num[p]++; //统计字第几个字符出现的次数
}
}
int Find(char str[]){ //找的话就简单了,但也是很巧妙的
int p = 0;
for(int i=0; str[i]; i++){ //for循环,把第二组样例的每一个字符串的字符从头到尾编译一遍
int n = str[i] - 'a';
if(trie[p][n] == 0){
return 0;
}
p = trie[p][n]; //一直跑到最后,得出最后一个字符是第几个输入的(第几个输入和建树有很大的关系,在插入中可以好好的模拟一下,也可以点开链接看一下)
}
return num[p]; 返回此时的字符串出现的次数;
}
int main(){
while(gets(str)){
if(str[0] == '\0')
break;
Insert(str);
}
while(~scanf("%s",str)) {
printf("%d\n",Find(str));
}
return 0;
}
指针实现
#include<bits/stdc++.h>
using namespace std;
struct Trie{ //字典树的定义
Trie *next[26];
int num; //以当前字符串为前缀的单词的数量
Trie(){ //构造函数
for(int i=0; i<26; i++) next[i] = NULL;
num = 0;
}
};
Trie root;
void Insert(char str[]){ //将字符串插入到字典树中
Trie *p = &root;
for(int i=0; str[i]; i++){ //遍历每一个字符
if(p -> next[str[i] - 'a'] == NULL) //如果该字符没有对应的节点
p -> next[str[i] - 'a'] = new Trie; //创建一个
p = p -> next[str[i] - 'a'];
p -> num++;
}
}
int Find(char str[]){
Trie *p = &root;
for(int i=0;str[i];i++){
if(p -> next[str[i] - 'a'] == NULL)
return 0;
p = p-> next[str[i] - 'a'];
}
return p -> num;
}
int main(){
char str[11];
while(gets(str)){
if(!strlen(str)) break; //输入了一个空行
Insert(str);
}
while(gets(str)) cout<<Find(str)<<endl;
return 0;
}