Trie字符串统计(每周一类)

        这节课我们学习Trie字符串。这个算法的主要应用就是字符串的快速存储和查找。我们通过下面这个题来讲 Tire字符串统计 ,另外说个题外话,本人是从ACwing里学习的算法知识,希望大家支持一下y总(ACwing大佬),如果觉得我这里的知识讲得不够全面,可以去网站里付费学习。

        Trie字符串统计

来分析一下这道题:

        第一步,理解题意:这道题需要输入一个数字n,表示操作的数量,之后输入n行操作,操作分为两种,一种是插入操作,另一种是查询操作,查询被查询的字符串有多少个,输出数字。

        第二步,暴力破解:如果暴力地来做的话,比较简单的就是无向图了,直接存入数据。

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <cstring>

using namespace std;
const int N = 100010;

int main(){
    char op[2];
    char str[N];
    int n;
    unordered_map <string,int> at;
    scanf("%d",&n);
    while(n --){
        scanf("%s%s",op,str);
        if(op[0] == 'I') {
            at[str] ++;
        }
        else{
            printf("%d\n",at[str]);
        }
    }
    return 0;
}

        还是比较简单易懂的,就是如果插入,就让值加一,如果查询,就直接输出。

        第三步,算法优化:由于我们这节课主要学习的是Trie,那么我们还是用这个方法做一下。原理很简单,就是构造一个树,使每一个字符从前向后,由根节点向子节点延伸,在结束的位置做上标记,用来查询。如图:如果需要分别插入abcd,abc,acef,ccd这四个字符串,那么树应该张成这样

      

        左侧的数字表示这个串的数量

我们看一下代码

#include <algorithm>
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx;
char str[N];

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 quary(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;
    cin >> n;
    for(int i = 0 ; i < n; i ++ ){
        char op[2];
        scanf("%s%s",op,str);
        if(op[0] == 'I') insert(str);
        else printf("%d\n",quary(str));
    }
    return 0;
}

        插入和查找都各自写了一个函数,但大体上都是一样的,我们一个一个来看。

        int p = 0; 设置一个变量 p ,用来记录位置,int son[N][26], cnt[N], idx; 设置son数组,来存储Trie,cnt 存储字符串的数量,idx 用来进行枚举。char str[N]; 用来记录字符串。在插入的循环中,int u = str[i] - 'a'; 表示将第 i 个字符转换成0-26个数字中的一个,if(!son[p][u]) son[p][u] =  ++idx; 如果之前没有存入这个字符串中的这个字符,那么就创建一个,(由于idx是动态增加的,所以在son中的位置也是动态改变的),p = son[p][u];  将下一个字符定到son中一个新的位置上。 cnt[p] ++; 在最后,记录这个字符串

        在查找的过程中也是一样,只不过是 if(!son[p][u]) return 0; 中,如果没有找到这个字符,那么就返回 0,表示没有这个字符串。

        如果想要深刻理解,建议自己手动模仿一下过程,如果想要速成,那么就把每句话的含义理解,会默写即可。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值