29.Acwing基础课第835题-简单-Trie字符串统计

29.Acwing基础课第835题-简单-Trie字符串统计

题目描述

维护一个字符串集合,支持两种操作:

  1. I x 向集合中插入一个字符串 x;
  2. Q x 询问一个字符串在集合中出现了多少次。

共有 N个操作,所有输入的字符串总长度不超过 105,字符串仅包含小写英文字母

输入格式

第一行包含整数 N,表示操作数。

接下来 N行,每行包含一个操作指令,指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x在集合中出现的次数。

每个结果占一行。

数据范围

1≤N≤2∗104

输入样例:

5
I abc
Q abc
Q ab
I ab
Q ab

输出样例:

1
0
1

代码:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<cstdio>
#include<string>
using namespace std;

const int N = 100010;

//idx相当于一个分配器,如果需要加入新的结点就用++idx分配出一个下标
//cnt[x]表示以x号结尾的单词多少个
//idx是有值的节点的个数
int son[N][26], cnt[N], idx;//下标是0的点,既是根节点,又是空节点
char str[N];

void insert(char str[])
{
    //每次都从第一个结点开始遍历
    int p = 0;
    for (int i = 0; str[i]; i++)
    {
        //用数字0~25代表a~z
        int u = str[i] - 'a';
        //判断这个结点是否存在这个字母,如果不存在的话,新创一个结点存储该字母
        //p表示的是第几个结点,u表示的是哪个字母,如果son[p][u]不为空就证明有以这个字母为值的子结点
        //它代表的值就是指向了该子结点,即说明了第几个结点是它的子结点
        //如son[2][1]=3,表示结点2有一个值为b(第二个数字代表的是a~z)的子结点,是结点3
        if (!son[p][u]) son[p][u] = ++idx;
        //令son[p][u]设置为父结点
        p = son[p][u];
    }

    //以这个节点为末尾的字符串个数加1
    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];
}

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;
}

分析

简介:

Trie又称字典树,前缀树,是一种支持插入和查找字符串的多叉树,每个节点对应一个字符,节点编号各不相同,根节点为0,其它节点编号用于标识路径,边表示字符

使用trie用于维护字符串集合,支持两种操作
1:void insert(char[]) 向集合中插入一个字符串
2:int query(char[]) 查询集合中莫格字符串出现的次数

数据储存:

子节点数组:

int son[p][u]储存p号节点沿着u这条边走到的子节点编号

第二维储存边,边为26个小写字母a~z的映射为0~25,即每个节点至多有26个分叉

比如:
son[0][2]=1表示从0号节点(根节点)沿c边走到的节点是1号节点

son[1][0]=2表示从1号节点沿着a边走到的节点是2号节点

son[2][19]=3表示从2号节点沿着t边走到的节点是3号节点

计数数组:

int cnt[p]储存以p号节点为结尾的字符串插入次数(每个节点是唯一的)

cnt[3]=1表示以3号节点为结尾的字符串数量插入了1次(即”cat”插入1次)

节点编号:

int idx全局变量用于给节点进行编号,每插入一个节点,就++,根节点和空节点都为NULL

插入流程:

1.空树有且仅有一个根节点,编号为0

2.从根节点开始遍历,枚举待插入串的每个字符同时转换成映射值
如果有子节点(有路径),指针p走到子节点
如果没有(无路径),先使用idx创建新的子节点,指针p再走到子节点

3.在字符串最末字符代表的节点处更新次数

模拟一下:
向空树中先后插入
cat
car
busy
cate

查找:

1.从根节点开始遍历,扫描字符串

2.如果无字符s[i],结束查找并直接返回0

3.如果有字符s[i],继续扫描查找,直到词尾匹配,则返回cnt[p]

参考资料:Trie(前缀树,字典树) - AcWing

posted @ 2026-04-05 13:03  CodeMagicianT  阅读(1)  评论(0)    收藏  举报