每日两题

每日两题

计划每天打卡一道acwing上的题和一道leetcode上的题。

acwing

题目名:

  1. Trie字符串统计

题面:

维护一个字符串集合,支持两种操作:
I x 向集合中插入一个字符串 x;
Q x 询问一个字符串在集合中出现了多少次。
共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。
输入格式
第一行包含整数 N,表示操作数。
接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。
输出格式
对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。
每个结果占一行。
数据范围:
1≤N≤2∗104
输入样例:
5
I abc
Q abc
Q ab
I ab
Q ab
输出样例:
1
0
1

思路:

第一次遇到这种题(太菜了ORZ),看了讲解才知道这类题叫字典树,经常用于字符串集合中。
字典树,顾名思义,就是将各个字符串逐个字符地从根节点像树一样展开,最终形成一个字典形式的数(就像查字典的时候一样,从第一个字母开始定位,到第二个字母……)。其中,根结点是空的,即不放字母(当字典的的封面)。而且需要借助标记来标志各个字符串结束的位置。此标记可以用来记录同样到此处的字符串的个数。
具体如下图:
在这里插入图片描述hhh

可以发现,借助字典树,可以方便地对字符串数组中的各字符串进行计数,只需获得对应”五角星“位置的计数。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
int son[N][26],cnt[N],idx;
void insertt(char x[])
{
    int p=0;
    for(int i=0;x[i];i++)
    {
        int u=x[i]-'a';//映射到0-25这个区间,和son数组第二维对应
        if(!son[p][u])//字典树中这个位置尚没有字母
            son[p][u]=++idx;//把下标给该字母
        p=son[p][u];//不论该字母是新加的还是树中本来就有,都要沿着树下移。
    }
    cnt[p]++;//此时的p是该字符串的结尾点在整个字典树中的位置。
}
int queryy(char x[])
{
    int p=0;
    for(int i=0;x[i];i++)
    {
        int u=x[i]-'a';
        if(!son[p][u])//字典树中这个位置尚没有字母,说明集合中没有这个字符串,直接返回0。
            return 0;
        p=son[p][u];//若该字母尚且还在树中,下移
    }
    return cnt[p];//返回该字符串在集合中的个数。p含义同上。
}
int main()
{
    int n;
    cin>>n;
    char op[2],str[N];//通过%s输入会在结尾自动补\0,故op字符数组需要多一个字节。
    while(n--)
    {
        scanf("%s%s",op,str);
        if(op[0]=='I')
            insertt(str);
        else
            cout<<queryy(str)<<endl;
    }
    return 0;
}

分析:

这代码我看了半天才看得差不多……
先试着理解一下:
总体思想是用一个总字符串长度的二维数组来刻画这个字典树。
由于题面中说明所有插入的字符串加起来不超过105,而且各字符都为小写字母,定义son[N][26]该数组第一维表示某字符串的一个字母在字典苏中的父节点所处的位置,第二维表示这个字母是哪个,该二维数组的值是该字母所处的位置。cont[N] 用来记录“五角星”位置的个数。idx全局变量,从头划到尾,所以不会重复,用来标记每一个字母的位置。(表述还是不太清楚)
剩余可以参考代码中注释。
用数组模拟树确实有点难以理解。多看看希望会好点……(ORZ)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值