南昌理工学院acm集训队
简介:
字典树:高效地存储和查找字符串集合的数据结构。
下面介绍字典树也叫前缀树
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较。若要在n个字符串中查找某个字符串,如果使用暴力方法就需要逐个匹配字符串,复杂度是O(n * m),m是字符串平均长度。还有一种比较快的方法就是字典树,像查单词那样,一次找一个字母,查找任意单词,复杂度为O(m),m是查询或插入字符串的长度。
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
最长公共前缀
对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为当时公共祖先问题。
例题:HDU - 1251 和 acwing 字符串统计https://www.acwing.com/blog/content/277/
统计难题
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262140/131070 K (Java/Others)
Total Submission(s): 80591 Accepted Submission(s): 28366
Problem Description
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.
注意:本题只有一组测试数据,处理到文件结束.
注意:本题只有一组测试数据,处理到文件结束.
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana
band
bee
absolute
acm
ba
b
band
abc
Sample Output
2
3
1
0
题解:
用数组实现字典树
#include<iostream>
using namespace std;
int tree[1000000][26];
int num[1000000]={0};
char word[11];
int pos=1;
void Insert()
{
int c=0;
for(int i=0;word[i];i++)
{
int n=word[i]-'a';
if(trie[c][n]==0)
{
trie[c][n]=pos++;
}
c=trie[c][n];
num[c]++;
}
}
int Query()
{
int c=0;
for(int i=0;word[i];i++)
{
int n=word[i]-'a';
if(trie[c][n]==0)
return 0;
c=trie[c][n];
}
return num[c];
}
int main()
{
while(gets(word))
{
if(word[0]==NULL)
break;
Insert();
}
while(gets(word))
{
cout<<Find()<<endl;
}
return 0;
}
#include<iostream>
using namespace std;
const int N=1e5+10;
int idx=0,trie[N][26],cnt[N];
char str[N];
void Insert(char str[])
{
int p=0;
for(int i=0;str[i];i++)
{
int c=str[i]-'a';
if(!trie[p][c])
trie[p][c]=++idx;
p=trie[p][c];
}
cnt[p]++;
}
int Query(char str[])
{
int p=0;
for(int i=0;str[i];i++)
{
int c=str[i]-'a';
if(!trie[p][c])
return 0;
p=trie[p][c];
}
return cnt[p];
}
int main()
{
int n;
cin>>n;
while(n--)
{
char x;
cin>>x>>str;
if(x == 'I')
Insert(str);
else
printf("%d\n",Query(str));
}
return 0;
}