LeetCode 面试经典 150_字典树_添加与搜索单词 - 数据结构设计(96_211_C++_中等)

LeetCode 面试经典 150_字典树_添加与搜索单词 - 数据结构设计(96_211_C++_中等)

题目描述:

请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

实现词典类 WordDictionary :

  • WordDictionary() 初始化词典对象
  • void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
  • bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word
    中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。

输入输出样例:

示例 1:
输入

"WordDictionary","addWord","addWord","addWord","search","search","search","search"

\[\],\["bad"\],\["dad"\],\["mad"\],\["pad"\],\["bad"\],\[".ad"\],\["b..."\]

输出

null,null,null,null,false,true,true,true

解释

WordDictionary wordDictionary = new WordDictionary();

wordDictionary.addWord("bad");

wordDictionary.addWord("dad");

wordDictionary.addWord("mad");

wordDictionary.search("pad"); // 返回 False

wordDictionary.search("bad"); // 返回 True

wordDictionary.search(".ad"); // 返回 True

wordDictionary.search("b..."); // 返回 True

提示:

1 <= word.length <= 25

addWord 中的 word 由小写英文字母组成

search 中的 word 由 '.' 或小写英文字母组成

最多调用 104 次 addWord 和 search

题解:

解题思路:

思路一(字典树):

1、实现思路如下
插入单词

  • 从左到右插入这个单词的每个字母,若当前字母不存在字典树中(注意child是0~25,若child为nullptr则不存在),创建结点
  • 若为最后一个单词则进行标记isEnd=true。

查找单词

因单词中包含'.',所以我们要分两种情况讨论,从左到右查找这个单词的每个字符。

  • 若当前位置为字母,则查找node[word[i]-'a']存不存在,若存在则继续查找,若不存在则返回false
  • 若当前位置为'.',我们需要挨个判断此节点的所有儿子结点的分支。首先此节点的儿子结点不能为nullptr,其次递归的匹配其儿子结点,若匹配成功则返回true,否则返回false

需要非常注意一点字典树的 根结点 不存储任何信息。

2、复杂度分析:

① 时间复杂度:O(26k ·L),假设在最坏情况下字典树的每个节点都有26个子节点,如果遇到 个 ".",则为每个.都会进行 26 次递归。

② 空间复杂度:O(N×L),O(N×L),其中 N 是独立单词的数量,L 是单词的平均长度。

代码实现

代码实现(思路一(字典树)):
cpp 复制代码
class WordDictionary {
private:
    // 定义字典树的节点结构体(TrieNode)
    struct TrieNode
    {
        vector<TrieNode*> child; // 子节点数组,表示26个字母的子节点
        bool isEnd; // 标记当前节点是否为某个单词的结束节点
        TrieNode(): child(26, nullptr), isEnd(false) {} // 构造函数,初始化子节点数组为26个nullptr,并将isEnd初始化为false
    };

    TrieNode *root; // 根节点

    // 插入单词的函数
    void insert(TrieNode *root, const string &word){
        TrieNode *node = root;
        // 遍历单词中的每个字符
        for (auto c : word) {
            // 计算字符对应的索引,并检查当前字符的子节点是否为空
            if (node->child[c - 'a'] == nullptr) {
                // 如果为空,说明该字符路径还没有建立,创建新的节点
                node->child[c - 'a'] = new TrieNode();
            }
            // 将当前节点指向下一个字符的子节点
            node = node->child[c - 'a'];
        }
        // 单词遍历完成后,将当前节点的isEnd标记为true,表示这是一个完整的单词
        node->isEnd = true;
    }
    
    // 搜索单词的深度优先搜索(DFS)函数
    bool dfs(string &word, TrieNode *node, int index){
        // 如果遍历到单词的末尾,返回当前节点是否为单词的结束节点
        if (index == word.size()){
            return node->isEnd;
        }
        
        // 如果当前字符是'.',可以匹配任意字符
        if (word[index] == '.'){
            // 遍历当前节点的所有子节点
            for (auto &child : node->child){
                // 对每个非空子节点递归进行DFS
                if (child != nullptr && dfs(word, child, index + 1)){
                    return true; // 如果某个子节点匹配成功,返回true
                }
            }
            return false; // 如果所有子节点都无法匹配,返回false
        } else {
            // 如果当前字符不是'.',则检查当前节点对应字符的子节点是否为空
            if (node->child[word[index] - 'a'] == nullptr) {
                return false; // 如果没有对应的子节点,返回false
            }
            // 否则继续递归搜索下一个字符
            return dfs(word, node->child[word[index] - 'a'], index + 1);
        }
    }

public:
    // 构造函数,初始化根节点
    WordDictionary() {
        root = new TrieNode();
    }
    
    // 添加一个单词到字典中
    void addWord(string word) {
        insert(root, word); // 调用插入函数
    }
    
    // 搜索单词(支持'.'通配符)
    bool search(string word) {
        return dfs(word, root, 0); // 从根节点开始递归DFS
    }
};

LeetCode 面试经典 150_字典树_添加与搜索单词 - 数据结构设计(96_211原题链接

欢迎大家和我沟通交流(✿◠‿◠)

相关推荐
想用offer打牌2 小时前
一站式了解http1.1,http2.0和http3.0
后端·网络协议·面试
dragoooon342 小时前
[C++——lesson26.「多态」]
java·c++·学习方法·多态
jun_不见2 小时前
面试官:你能说下订阅发布模式么,怎么在VUE项目中实现一个类似eventBus的事件总线呢
前端·javascript·面试
爱吃KFC的大肥羊2 小时前
Redis 基础完全指南:从全局命令到五大数据结构
java·开发语言·数据库·c++·redis·后端
踏浪无痕3 小时前
基于Nacos的轻量任务调度方案 —— 从 XXL-Job 的痛点说起
后端·面试·架构
charlie1145141913 小时前
现代C++工程实践:简单的IniParser4——实现ini_parser
开发语言·c++·笔记·学习·工程
西西弗Sisyphus3 小时前
C++ 实现支持 32 位和 64 位进程的模块枚举
开发语言·c++·操作系统
月明长歌3 小时前
【码道初阶】【LeetCode 572】另一棵树的子树:当“递归”遇上“递归”
算法·leetcode·职场和发展
月明长歌3 小时前
【码道初阶】【LeetCode 150】逆波兰表达式求值:为什么栈是它的最佳拍档?
java·数据结构·算法·leetcode·后缀表达式