• LeetCode 热题 100 | 图论(三)


    目录

    1  前缀树

    1.1  什么是前缀树

    1.2  如何构建前缀树

    2  208. 实现 Trie(前缀树)


    菜鸟做题,语言是 C++

    前缀树

    1.1  什么是前缀树

    前缀树,也被称作字典树(Trie)或者键树,是一种用于检索字符串数据集中的键的树形数据结构。在前缀树中,每一个节点都代表着一个字符,而路径则代表着字符串。这种数据结构特别适用于自动补全、拼写检查以及自然语言处理等场景。

    1.2  如何构建前缀树

    根据前缀树的定义,其节点的结构应该为:

    1. class Trie {
    2. private:
    3. vector children;
    4. bool isEnd;
    5. }
    • 一个 Trie 节点表示一个字母
    • children 用于存储下一个字母的 26 种可能
    • isEnd 用于表示当前字母是否为某个单词的结尾

    这里我们将前缀树定义为 Trie 类而不是 Trie 结构体,是因为它还将提供一些方法。

    假设我们需要存储 appleapp 这两个单词,则可以构建如下 Trie:

    ① apple:由于此前还没有种树,因此我们需要创建 root 根节点。接着,因为第一个字母是 a,所以我们为根节点的 children[0] 创建子节点。第二个字母是 p,所以我们为子节点的 children[15] 创建子节点。以此类推。直到字母 e,我们只需要将它所对应的子节点的 isEnd 置为 True 即可。

    ② app:我们可以直接从 root 根节点开始查询。针对第一个字母 a,由于根节点的 children[0] 已经有子节点了,因此我们直接去找子节点。针对第二个字母 p,由于子节点的 children[15] 已经有子节点了,因此我们直接去找子节点。以此类推。直到最后一个字母 p,我们只需要将它所对应的子节点的 isEnd 置为 True 即可。

    图中的 26 表示,children 容器中的每个节点(字母)都可以拥有自己的子节点(字母)。

    2  208. 实现 Trie(前缀树)

    ① 初始化节点:

    Trie() : children(26), isEnd(false) {}

    ② 插入新的字符串:

    1. void insert(string word) {
    2. Trie * node = this;
    3. for (auto & ch : word) {
    4. ch -= 'a';
    5. if (node->children[ch] == nullptr)
    6. node->children[ch] = new Trie();
    7. node = node->children[ch];
    8. }
    9. node->isEnd = true;
    10. }

    this 指针指向的是当前的 Trie 对象,即第一个被创建的节点,也就是根节点。

    ③ 查询字符串:

    1. bool search(string word) {
    2. Trie * node = this;
    3. for (auto & ch : word) {
    4. ch -= 'a';
    5. if (node->children[ch] == nullptr)
    6. return false;
    7. node = node->children[ch];
    8. }
    9. if (node->isEnd) return true;
    10. return false;
    11. }

    ④ 查询字符串前缀:

    1. bool startsWith(string prefix) {
    2. Trie * node = this;
    3. for (auto & ch : prefix) {
    4. ch -= 'a';
    5. if (node->children[ch] == nullptr)
    6. return false;
    7. node = node->children[ch];
    8. }
    9. return true;
    10. }

    和 “查询字符串” 几乎没有区别,只是不要求最后一个字母是某字符串的结尾。

    1. class Trie {
    2. private:
    3. vector children;
    4. bool isEnd;
    5. public:
    6. Trie() : children(26), isEnd(false) {}
    7. void insert(string word) {
    8. Trie * node = this;
    9. for (auto & ch : word) {
    10. ch -= 'a';
    11. if (node->children[ch] == nullptr)
    12. node->children[ch] = new Trie();
    13. node = node->children[ch];
    14. }
    15. node->isEnd = true;
    16. }
    17. bool search(string word) {
    18. Trie * node = this;
    19. for (auto & ch : word) {
    20. ch -= 'a';
    21. if (node->children[ch] == nullptr)
    22. return false;
    23. node = node->children[ch];
    24. }
    25. if (node->isEnd) return true;
    26. return false;
    27. }
    28. bool startsWith(string prefix) {
    29. Trie * node = this;
    30. for (auto & ch : prefix) {
    31. ch -= 'a';
    32. if (node->children[ch] == nullptr)
    33. return false;
    34. node = node->children[ch];
    35. }
    36. return true;
    37. }
    38. };

  • 相关阅读:
    SpringBoot 全局异常处理
    Linux PCIe驱动框架分析(第一章)
    人生苦短,我用Python 七:如何在flask文档在return后,继续执行文档函数?
    深入探讨栈数据结构:定义、特性和应用
    WPF基础的一些基本操作
    windows安装pytorch
    从计算机组成的视角认识JVM的内存分配在HotSpot虚拟机上的实现
    猿创征文|瑞吉外卖——管理端_订单明细
    项目管理之八大绩效域------笔记(五)
    基于springboot高校社团管理系统
  • 原文地址:https://blog.csdn.net/m0_64140451/article/details/136435907