码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 字典树原理与实现


    文章目录

    • 字典树
      • 一、字典树节点
      • 二、字典树的插入
      • 三、字典树的查询
      • 四、算法练习
        • [LeetCode 2416. 字符串的前缀分数和](https://leetcode.cn/problems/sum-of-prefix-scores-of-strings/)

    字典树

    字典树(trie),又称前缀树,或单词查找树,是一棵专用于查找单词或单词前缀是否存在的树。

    一、字典树节点

    字典树的节点一般包含一个字典树节点指针数组,用来存储它的孩子。
    在有些情况下,还需要加入is_end用于标记该节点表示某个单词的最后一个字符。

    class Trie
    {
        vector ch;
        // bool is_end;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    当所有单词都由小写字母构成时,数组的大小为26,即26个小写字母。

    image-20220919153007569


    二、字典树的插入

    以插入单词an为例:

    image-20220919153641772

    第一个字母为a,所以在根节点处为a创建一个孩子节点,将孩子节点的地址填入ch数组下标为'a'-'a'处。此时我们递归至新创建的孩子节点,处理下一个字母。

    第二个字母为n,所以为n创建一个孩子节点,并将孩子节点的地址填入ch数组下标为'n'-'a'处。

    如果再插入app呢:

    image-20220919154241597

    根节点处a的孩子节点已经创建,因此递归至第二层。

    第二层p的孩子节点为空,因此new一个,递归至第三层。

    第三层p孩子节点为空,因此new一个,递归结束。

    总结:

    插入操作是一种递归式的,第一个字母对应根节点,第二个字母对应第一个字母对应位置的孩子节点。

    但是,一般为了效率,使用非递归的方式进行插入。

    void insert(const string& s)
    {
        int n = s.size();
        Trie* trie = this; // 当前所在的字典树节点
        for (int i = 0; i < n; ++i)
        {
            if (trie->dic[s[i] - 'a'] == nullptr)
                trie->dic[s[i] - 'a'] = new Trie;
            trie = trie->dic[s[i] - 'a'];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    三、字典树的查询

    与插入类似,插入在对应位置为空时,创建一个新结点,而查询在对应位置为空时,表明不存在对应的单词或前缀。

    比如,在上述字典树的基础上查询an时,从根节点递归下来,没有空节点,说明an是存在的。

    image-20220919155113394

    而查询ao时,在第二层发现o为空,因此判定:ao不存在。

    image-20220919155205478

    bool query(const string& s)
    {
        int n = s.size();
        Trie* trie = this; // 当前所在的字典树节点
        for (int i = 0; i < n; ++i)
        {
            if (trie->cnt[s[i] - 'a'] == nullptr)
                return false;
            trie = trie->dic[s[i] - 'a'];
        }
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    四、算法练习

    LeetCode 2416. 字符串的前缀分数和

    class Trie
    {
        vector dic;
        vector cnt; // 记录以c为最后一个字符的前缀有多少个
    public:
        Trie()
        {
            dic.resize(26, nullptr);
            cnt.resize(26, 0);
        }
        void add(const string& s)
        {
            int n = s.size();
            Trie* trie = this;
            for (int i = 0; i < n; ++i)
            {
                if (trie->dic[s[i] - 'a'] == nullptr)
                    trie->dic[s[i] - 'a'] = new Trie;
                trie->cnt[s[i] - 'a']++;
                trie = trie->dic[s[i] - 'a'];
            }
        }
        int query(const string& s)
        {
            int n = s.size();
            Trie* trie = this;
            int res = 0;
            for (int i = 0; i < n; ++i)
            {
                res += trie->cnt[s[i] - 'a'];
                trie = trie->dic[s[i] - 'a'];
            }
            return res;
        }
    };
    class Solution 
    {
        Trie trie;
    public:
        vector sumPrefixScores(vector& words) 
        {
            for (auto& word : words)
            {
                trie.add(word);
            }
            vector res;
            for (auto& word : words)
            {
                res.emplace_back(trie.query(word));
            }
            return res;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
  • 相关阅读:
    开发这么久,gradle 和 gradlew 啥区别、怎么选?
    免安装Android Studio使用adb连接手机设备或模拟机进行真机调试
    【原型与原型链】初识原型与原型链~
    react项目中使用mobx
    R语言使用glm函数构建逻辑回归模型(logistic)、使用subgroupAnalysis函数进行亚组分析并可视化森林图
    Python识别验证码----谷歌reCapture 3*3验证码
    对‘QBasicAtomicInt_fetchAndAddOrdered(int volatile*, int)’未定义的引用
    C/C++ 排序算法总结
    背包问题
    安装Linux虚拟机——以ubuntukylin-16.04.7-desktop-amd64.iso为例
  • 原文地址:https://blog.csdn.net/Wyf_Fj/article/details/126935636
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号