来源:HDU1251
这一题如果用最普通的匹配,那么,我们需要每一次判断的时候都进行一次遍历,这样不仅时间浪费了,而且太多的时候是重复计算。同时,由于是比较的前缀,所以也不可能用KMP来节约时间。我们这里只能使用字典树。
直接用模板,道理很简单的,这里不细讲,关键点见注释。
代码(VJ提交):(此代码并没有过,MLE,但是模板是这样的,网上大部分题解也是这样写的,但是这样是过不了的。。。)
#include<iostream>
#include<cstdio>
#include<cstring>
#include <cstdlib>//用于free
struct Trie
{
int sum;
Trie *next[26];//表示后继的字母。。。
}*root;
void Insert(char *s)
{
Trie *p,*t;
int i,n = strlen(s);
p = root;
for (i = 0;i < n;i ++)
{
if (p->next[s[i]-'a'] == NULL)//如果之前还没来过
{
t = new Trie;
t->sum = 1;
for (int j = 0;j < 26;j ++)
t->next[j] = NULL;
p->next[s[i]-'a'] = t;
}
else p->next[s[i]-'a']->sum ++;//来过的话,节点+1
p = p->next[s[i]-'a'];
}
}
int Search(char *s)
{
Trie *p;
int i,n = strlen(s);
p = root;
for (i = 0;i < n;i ++)
{
if (p->next[s[i]-'a'] == NULL)//一旦哟偶一个没有,直接判定为不是
return 0;
p = p->next[s[i]-'a'];
}
return p->sum;
}
void Release(Trie *p)//我MLE之后用的,就是用递归的方法进行free但是还是无缘无故的MLE,代码很好理解
{
if (p == NULL)
return ;
for (int i = 0;i < 26;i ++)
if (p->next[i] != NULL)
Release(p->next[i]);
free(p);
root = NULL;
return ;
}
void Init()
{
root = new Trie;
root->sum = 0;
for (int i = 0;i < 26;i ++)
root->next[i] = NULL;
}
int main ()
{
char str[15];
Init();
while (1)
{
gets(str);
if (strcmp(str,"")==0) break;
Insert(str);
}
while (~scanf ("%s",str))
printf ("%d\n",Search(str));
Release(root);
return 0;
}
我尝试用STL的map过了,这是AC代码:
#include <iostream>
#include <map>
#include <cstring>
#include <string>
using namespace std;
int main()
{
int i, len;
char str[10];
map<string, int> m;
while( gets(str) )
{
len = strlen(str);
if ( !len )
{
break;
}
for(i = len; i > 0; i--)
{
str[i] = '\0';
m[str]++;
}
}
while( gets(str) )
{
cout << m[str] << endl;
}
return 0;
}
STL参见我的其他文章。。。