时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。
这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能对于每一个我给出的字符串,都在这个词典里面找到以这个字符串开头的所有单词呢?”
输入
输入的第一行为一个正整数n,表示词典的大小,其后n行,每一行一个单词(不保证是英文单词,也有可能是火星文单词哦),单词由不超过10个的小写英文字母组成,可能存在相同的单词,此时应将其视作不同的单词。接下来的一行为一个正整数m,表示小Hi询问的次数,其后m行,每一行一个字符串,该字符串由不超过10个的小写英文字母组成,表示小Hi的一个询问。
在20%的数据中n, m<=10,词典的字母表大小<=2.
在60%的数据中n, m<=1000,词典的字母表大小<=5.
在100%的数据中n, m<=100000,词典的字母表大小<=26.
输出
对于小Hi的每一个询问,输出一个整数Ans,表示词典中以小Hi给出的字符串为前缀的单词的个数。
样例输入
5
babaab
babbbaaaa
abba
aaaaabaa
babaababb
5
babb
baabaaa
bab
bb
bbabbaab
样例输出
1
0
3
0
0
首先给出trie树的原理:trie树是以空间换取时间,利用字符串的公共前缀来降低查询开销。举个例子:add,addition,这两个单词,他们的公共前缀是add,应用trie数进行存储的时候,add只会被存储一次,如果以add为前缀的单词很多,这样就节省了很多的存储空间。
trie树的性质:
1,字符种数决定trie中branch的个数,以单词为例,共有26个英文单词,那么每个节点中会有26个指针域。
2,branch数组的下标代表字符相对于a的相对位置。
3,插入和查询的时间复杂度均与给定单词的长度len成正比,即为:o(len)。
4,每个节点附设一个count域,若count域被初始化为0,如果在插入所有单词之后,遍历trie树的时候,count不等于0,则表示从根节点到此节点的
每个字母连接成的单词出现的次数。
如图所示,该trie树存有abc、d、da、dda四个字符串,如果是字符串会在节点的尾部进行标记(count!=0)。没有后续字符的branch分支指向NULL:
代码:
#include <iostream>
#include <string.h>
using namespace std;
#define MaxNum 26
typedef struct sTrieNode
{
int count;
bool IsWord;
struct sTrieNode* next[MaxNum];
}TrieNode;
TrieNode* CreateTrieNode()
{
TrieNode*NewTrie=new TrieNode;
NewTrie->count=0;
NewTrie->IsWord=false;
memset(NewTrie->next, NULL , sizeof(NewTrie->next));
return NewTrie;
}
void InsertWord(TrieNode* root,char* word)
{
TrieNode *Node=root;
int Index;
char *str=word;
while (*str!='\0')
{
Index=*str-'a';
if (Node->next[Index]==NULL)
{
Node->next[Index]=CreateTrieNode();
}
Node=Node->next[Index];
Node->count++;
str++;
}
Node->IsWord=true;
}
int FindWord(TrieNode* root, char* word)
{
TrieNode*Node = root;
char *str = word;
int Index;
while( *str!='\0')
{
Index =*str - 'a';
Node =Node->next[Index];
if(Node == NULL)
return 0;
str++;
}
return Node->count;
}
int main()
{
TrieNode*Root=CreateTrieNode();
char word[10];
int num;
cin>>num;
while (num--)
{
cin>>word;
InsertWord(Root,word);
}
cin>>num;
while (num--)
{
cin>>word;
cout<<FindWord(Root,word)<<endl;
}
return 0;
}