【面试/竞赛必备算法】字典树(tire)

这里是paoxiaomo,一个现役ACMer,之后将会持续更新算法笔记系列以及笔试题题解系列

本文章面向想打ICPC/蓝桥杯/天梯赛等程序设计竞赛,以及各个大厂笔试的选手

感谢大家的订阅➕ 和 喜欢💗

这次的蓝桥杯浙江省省赛出现了字典树的题(详情【2024浙江省蓝桥杯C++B组省赛】题解A-D(含题面)-CSDN博客),因此这次我们来详细讲解一下字典树。

字典树通常用于实现词典或者前缀搜索。它的每个节点代表一个字符,从根节点到每个节点的路径构成一个单词。字典树常常用于统计,保存大量字符串并且相比于别的字符串算法,它的统计只和正在被查询的字符串长度有关,在不少问题上优于哈希等其它字符串算法。

先说一下基本操作:

  • 插入操作: 将一个新的单词插入字典树中。从根节点开始,沿着单词的每个字符向下遍历,如果某个字符对应的子节点不存在,则创建新的子节点;最后标记最后一个字符节点为单词结束。

  • 查找操作: 在字典树中查找一个单词。从根节点开始,沿着单词的每个字符向下遍历,如果某个字符对应的子节点不存在,则说明字典树中不存在该单词;如果遍历完所有字符后,最后一个字符节点标记了单词结束,则说明该单词存在于字典树中。

  • 前缀搜索: 找到所有以某个给定前缀开头的单词。从根节点开始,沿着前缀的每个字符向下遍历,直到到达前缀的最后一个字符节点,然后通过DFS(深度优先搜索)遍历以该节点为根的子树,收集所有以该前缀开头的单词。

如何实现?

我们用tr[N][26]表示维护每个节点的子节点,num维护每个节点被经过的次数,tot代表节点总数,其中0是初始节点。即可实现插入/查询前缀数之和.

    int tr[N][26], tot, num[N];
    void inset(string s){
        int now = 0;
        for (int j = 0; j < s[i].size(); j++)
        { 
            if (!tr[now][s[i][j] - 'a'])
            {
                tr[now][s[i][j] - 'a'] = ++tot;//找不到就新开节点
            }
            now = tr[now][s[i][j] - 'a'];
            num[now]++;
        }
    }
    int find(string s){
        int now = 0;
        for (int j = 0; j < s[i].size(); j++)
        { 
            if (!tr[now][s[i][j] - 'a'])
            {
                break;//找不到相应节点就退出
            }
            now = tr[now][s[i][j] - 'a'];
            sum += num[now];
        }return sum
    }

如图,以上字典树可以代表着字符串集:aa,aba,ba,cc,caaa,cab,cba.可以尝试模拟一下建树过程加深理解。

除了表示字符之外,节点可能还存储其他信息,如该节点对应的字符是否是一个单词的结束,或者该单词在词典中出现的频率等。同时,字典树也是后缀自动机等高级字符串处理算法的前置知识。

关注博主,带你学习更多竞赛/笔试实用算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值