算法介绍
Trie树又叫字典树或者说前缀树
高效的存储和查找字符串集合的算法结构
主要有2种操作,存储字符串,查询字符串
模版题
主要思路分析
模版中主要有两个函数query函数和insert函数
其本质都是找字符串最后一个元素的编号idx
insert函数:如果没有该结点,就可以创建出,记录字符串最后一个元素的编号idx,用p 存储
在cnt[N]数组中,++,(cnt[idx]++)统计字符串出现的数量
query函数,找到字符串最后一个元素的编号idx,用p存储,然后通过cnt数组,可以得到该字符串出现的次数(cnt[p])
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
int son[N][26];
//字符串都是有小写字母组成,所以一个点,最多有26个子结点
//二维数组的行的范围是字符串大小的范围
//0表示根结点,为NULL, 如果该结点不存在,也是0
int cnt[N];
//存储的每个字符串,最后一个元素出现的次数-->该字符串出现的次数
int idx;
//每个结点都有独一唯一的idx
char str[N]; //字符串
void insert(char * str)
{
int p = 0;
//记录每个字符串的末尾元素-->记录该结点的idx
//也是二维数组的行
//字符串以 "/0" 结尾,可用做循环条件
for(int i = 0; str[i]; i++)
{
//以ASCII码记录 0~ 25
int u = str[i] - 'a';
//不存在这个结点,插入 (赋予结点唯一的idx)
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
//注意:这里不能用if else 语句,在做插入的时候,如果不存在,就插入新结点,更新下idx,要记录元素的idx
//存在,说明该结点不用插入,但还是要记录该结点的idx,区别于查询操作(可用if else 语句,就找到,找不到两种情况),当然查询操作也可不用
}
//记录该字符串出现的次数
cnt[p]++;
}
int query(char *str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
//该结点不存在,找不到,返回0
if(!son[p][u]) return 0;
p = son[p][u]; //记录下一个元素的idx
}
//循环结束,找到字符串尾元素的idx
return cnt[p];
}
int main()
{
int n;
scanf("%d", &n);
while(n--)
{
char op[2];
scanf("%s%s", op, str);
if( *op == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}