2021.4.14-刷题(前缀树或字典树(Trie))

题目链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree
题目描述:
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:

Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

示例:

输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 True
trie.search("app"); // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app"); // 返回 True

题解:
前缀树:
从二叉树说起
前缀树,也是一种树。为了理解前缀树,我们先从二叉树说起。
常见的二叉树结构是下面这样的:

class TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
}

可以看到一个树的节点包含了三个元素:该节点本身的值,左子树的指针,右子树的指针。
二叉树的每个节点只有两个孩子,那如果每个节点可以有多个孩子呢?这就形成了多叉树。多叉树的子节点数目一般不是固定的,所以会用变长数组来保存所有的子节点的指针。多叉树的结构是下面这样:

class TreeNode {
    int val;
    vector<TreeNode*> children;
}

对于普通的多叉树,每个节点的所有子节点可能是没有任何规律的。而本题讨论的「前缀树」就是每个节点的 children 有规律的多叉树。
前缀树
(只保存小写字符的)「前缀树」是一种特殊的多叉树,它的 TrieNode 中 chidren 是一个大小为 26 的一维数组,分别对应了26个英文字符 'a' ~ 'z',也就是说形成了一棵 26叉树。
前缀树的结构可以定义为下面这样。
里面存储了两个信息:
isWord 表示从根节点到当前节点为止,该路径是否形成了一个有效的字符串。
children 是该节点的所有子节点。


class TrieNode {
public:
    vector<TrieNode*> children;
    bool isWord;
    TrieNode() : isWord(false), children(26, nullptr) {
    }
    ~TrieNode() {
        for (auto& c : children)
            delete c;
    }
};

在构建前缀树的时候,按照下面的方法:

  1. 根节点不保存任何信息;
  2. 关键词放到「前缀树」时,需要把它拆成各个字符,每个字符按照其在 'a' ~ 'z' 的序号,放在对应的 chidren 里面。下一个字符是当前字符的子节点。
  3. 一个输入字符串构建「前缀树」结束的时候,需要把该节点的 isWord 标记为 true,说明从根节点到当前节点的路径,构成了一个关键词。

作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/fu-xue-ming-zhu-cong-er-cha-shu-shuo-qi-628gs/

题解:

class Trie {
private:
    bool isEnd;
    Trie* next[26];
public:
    /** Initialize your data structure here. */
    Trie() {
        isEnd = false;
        memset(next,0, sizeof(next));

    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Trie *node = this;
        for(char ch: word)
        {
            if(node->next[ch - 'a'] == NULL)
            {
                node->next[ch - 'a'] = new Trie();
            }
           node = node->next[ch - 'a'];
        }
        node->isEnd = true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Trie *node = this;
        for(char ch: word)
        {
            node = node->next[ch - 'a'];
            if(node== NULL)
                return false;
            
        }
        return node->isEnd;
       
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        Trie *node = this;
        for(char ch : prefix)
        {
            node = node->next[ch - 'a'];
            if(node == NULL)
                return false;

        }
       return true;

    }
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */

原文地址:https://www.cnblogs.com/ZigHello/p/14656953.html