• 【每日一题】实现 Trie (前缀树)


    在这里插入图片描述

    题目描述


    Trie的介绍
    208. 实现 Trie (前缀树)
    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

    提示:

    1 <= word.length, prefix.length <= 2000
    word 和 prefix 仅由小写英文字母组成
    insert、search 和 startsWith 调用次数 总计 不超过 3 * 104 次

    题解

    由于有插入apple,查看app是否插入的情况,所以需要flags来判断插入的是什么字符,我采取的是在末尾e处添加flag,表示为apple,并且e处添加flag一定表示的是apple被插入!
    这是因为每一个字符都开了一个26位的字符数组,通过映射只有apple会映射到这个点。
    在这里插入图片描述


    class Trie {
    public:
        struct Node {
            Node()
            {
                next.resize(26, nullptr);
                flags.resize(26,false);
            }
            vector<Node*> next;
            vector<bool> flags;
        };
        Node* root = nullptr;
        Trie() {
            //给一个哨兵位头节点
            root = new Node;
        }
        //未插入的部分就是nullptr,用来表示没有这个字符
        void insert(string word) {
            if (word.empty()) return;
            Node* cur = root;
            Node* parent = cur;
            for (int i = 0; i < word.size(); ++i)
            {
                //cur的a处是否有开
                if (cur->next[word[i] - 'a'] == nullptr)
                {
                    cur->next[word[i] - 'a'] = new Node;
                }
                parent = cur;
                cur = cur->next[word[i] - 'a'];
            }
            parent->flags[word.back() - 'a'] =true;//表示以parent结尾的才是真正插入的
        }
    
        bool search(string word) {
            Node* cur = root;
            if (cur == nullptr)
                return false;
    
            Node* parent = nullptr;
            for (int i = 0; i < word.size(); ++i)
            {
                if (cur->next[word[i] - 'a'] == nullptr)
                {
                    return false;
                }
                //检测下一个单次
                parent = cur;
                cur = cur->next[word[i] - 'a'];
            }
            if(parent->flags[word.back() - 'a'] == true)
            return true;
    
            return false;
        }
    
        bool startsWith(string prefix) {
            Node* cur = root;
            if (cur == nullptr) return false;
    
            for (int i = 0; i < prefix.size(); ++i)
            {
                if (cur->next[prefix[i] - 'a'] == nullptr)
                    return false;
    
                cur = cur->next[prefix[i] - 'a'];
            }
            return true;
        }
    };
    
    • 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
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    优化

    实际上没有必要指向上一个结构体添加flags数组了,实际上cur指向的已经是一个唯一的Node了,并且能够标识最后一个字符。

    class Trie {
    public:
        struct Node {
            Node()
            {
                next.resize(26, nullptr);
            }
            vector<Node*> next;
            bool flag = false;
        };
        Node* root = nullptr;
        Trie() {
            //给一个哨兵位头节点
            root = new Node;
        }
        //未插入的部分就是nullptr,用来表示没有这个字符
        void insert(string word) {
            if (word.empty()) return;
            Node* cur = root;
            for (int i = 0; i < word.size(); ++i)
            {
                //cur的a处是否有开
                if (cur->next[word[i] - 'a'] == nullptr)
                {
                    cur->next[word[i] - 'a'] = new Node;
                }
                cur = cur->next[word[i] - 'a'];
            }
            cur->flag=true;//表示以parent结尾的才是真正插入的
        }
    
        bool search(string word) {
            Node* cur = root;
            if (cur == nullptr)
                return false;
    
            for (int i = 0; i < word.size(); ++i)
            {
                if (cur->next[word[i] - 'a'] == nullptr)
                {
                    return false;
                }
                //检测下一个单次
                cur = cur->next[word[i] - 'a'];
            }
            if(cur->flag)
            return true;
    
            return false;
        }
    
        bool startsWith(string prefix) {
            Node* cur = root;
            if (cur == nullptr) return false;
    
            for (int i = 0; i < prefix.size(); ++i)
            {
                if (cur->next[prefix[i] - 'a'] == nullptr)
                    return false;
    
                cur = cur->next[prefix[i] - 'a'];
            }
            return true;
        }
    };
    
    • 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
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65



    end

    • 喜欢就收藏
    • 认同就点赞
    • 支持就关注
    • 疑问就评论
  • 相关阅读:
    JavaSE的思维导图
    C#实现二叉树的最大深度
    flinkdashboard未授权
    【MMDetection】MMDetection中AnchorGenerator学习笔记
    LeetCode 363 期周赛
    18 【Redux Toolkit】
    Vue脚手架Ⅱ(props配置,mixin混入,插件,scoped样式)
    如何理解有害菌,病原菌,致病菌?
    Rapid chain
    Vue项目中组件如何使用
  • 原文地址:https://blog.csdn.net/weixin_52344401/article/details/126280932