835. Trie字符串统计
Posted 幽殇默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了835. Trie字符串统计相关的知识,希望对你有一定的参考价值。
https://www.acwing.com/problem/content/description/837/
Trie的概念: 高效地存储和查找字符串集合的数据结构。
y神的模板:
int son[N][26], cnt[N], idx;
// 0号点既是根节点,又是空节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量
// 插入一个字符串
void insert(char *str)
{
int p = 0;
for (int i = 0; str[i]; i ++ )
{
int u = str[i] - 'a';
if (!son[p][u]) son[p][u] = ++ idx;
p = son[p][u];
}
cnt[p] ++ ;
}
// 查询字符串出现的次数
int query(char *str)
{
int p = 0;
for (int i = 0; str[i]; i ++ )
{
int u = str[i] - 'a';
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
首先要注意的一点就是: N代表的是输入的字符串总长度。
也就是说,这个Trie树的结点个数和是小于等于N的。
第二点 idx的含义:其实和单链表里的那个含义差不多,如下图我已经用绿笔标出了结点对应的idx的值
需要注意的一点就是我们的每一个点,对应的idx都是唯一的,这样我们再找儿子的过程中就不会有一对多的情形。
第三点son[N] [26] 的含义
很多小伙伴,不知道这个的含义是啥。其是只要带个案例模拟一边你就懂了。
例: son[0][u] 这个的含义就是根节点它的孩子u结点的下标,跟单链表里的next指针其实是一样的。
不过有区别的一点是我们的单链表它的孩子只有一个,是一条链子。
但是我们的Trie是后面可能有26个孩子(因为英文字母只有26个),即有26种路径可以选的单链表。
例: abc
其实只要把字符串的每条路径当成一个单链表,就十分的容易理解了。
最后cnt[p] 的含义
就是该字符串出现的次数。比如上图的: abc 这条字符串单链表已经到头了,那么我们就 cnt[p]++,
p代表的就是c字符所对应的idx,idx我已经说了它和一个字符是唯一对应的,这里的唯一对应不仅是字符对应的关系还有位置(即树的层数)。
因为第1层的" a " 和 第二层的 " a ” 是不同的。
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e5+10;
int cnt[N],son[N][26],idx;
void add(string s)
{
int p=0;
for(int i=0;i<s.size();i++)
{
int u=s[i]-'a';
if(!son[p][u]) son[p][u]=++idx;
p=son[p][u];
}
cnt[p]++;
}
int query(string s)
{
int p=0;
for(int i=0;i<s.size();i++)
{
int u=s[i]-'a';
if(!son[p][u]) return 0;
p=son[p][u];
}
return cnt[p];
}
int main(void)
{
int n; cin>>n;
while(n--)
{
string op,s; cin>>op>>s;
if(op=="I") add(s);
else cout<<query(s)<<endl;
}
return 0;
}
以上是关于835. Trie字符串统计的主要内容,如果未能解决你的问题,请参考以下文章