题意:给你一堆单词,现在有多次询问,每次询问求以给定字符串作为前缀的单词有多少个。
Sample Input
banana
band
bee
absolute
acm
ba
b
band
abc
Sample Output
2
3
1
0
有两种建树方法,一种动态一种静态。
一般来说静态更好一些。
动态代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 105;
char str[maxn];
struct node
{
int cnt;//根据需要变化,这里是记录有该前缀的数量
struct node *next[26];
//next是表示每层有多少种类的数,如果只是小写字母,则26即可,
//若改为大小写字母,则是52,若再加上数字,则是62了
node()
{
cnt = 0;
memset(next, 0, sizeof(next));
}
};
node *root = NULL;
void buildTrie(char *s)
{
node *p = root;
node *tmp = NULL;
int len = strlen(s);
for(int i = 0; i < len; i++)
{
if(p->next[s[i]-'a'] == NULL) //该前缀没出现过
{
tmp = new node;
p->next[s[i]-'a'] = tmp;
}
p = p->next[s[i]-'a'];
p->cnt++;
}
}
int findTrie(char *s)
{
node *p = root;
int len = strlen(s);
for(int i = 0; i < len; i++)
{
if(p->next[s[i]-'a'] == NULL) //不存在以该字符串为前缀
return 0;
p = p->next[s[i]-'a'];
}
return p->cnt;
}
void deleateTrie(node *cur)//动态字典树,有时会超内存, 这时就要记得释放空间了
{
for(int i = 0; i < 26; i++)
if(cur->next[i])
deleateTrie(cur->next[i]);
delete cur;
}
int main(void)
{
root = new node;
while(gets(str))
{
if(!strlen(str)) break;
buildTrie(str);
}
while(gets(str) != NULL)
printf("%d\n", findTrie(str));
return 0;
}
静态代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxnode = 1e6+5;
const int maxn = 27;
int sz, ch[maxnode][maxn], val[maxnode];
char str[15];
void init()
{
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void Insert(char *s)
{
int u = 0;
int len = strlen(s);
for(int i = 0; i < len; i++)
{
if(ch[u][s[i]-'a'] == 0)
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][s[i]-'a'] = sz++;
}
u = ch[u][s[i]-'a'];
val[u]++;
}
}
int Match(char *s)
{
int u = 0;
int len = strlen(s);
for(int i = 0; i < len; i++)
{
if(ch[u][s[i]-'a'] == 0)
return 0;
u = ch[u][s[i]-'a'];
}
return val[u];
}
int main(void)
{
init();
while(gets(str))
{
if(!strlen(str)) break;
Insert(str);
}
while(gets(str) != NULL)
printf("%d\n", Match(str));
return 0;
}