LeetCode之字典树

208. 实现 Trie (前缀树)

java 复制代码
class Trie {
    // 记录该字母的下一位所有可能的字母坐标
    private Trie[] children;
    // 该字母是否为最后一个字母
    private boolean isEnd;

    public Trie() {
        // 初始化 26 个字母的子节点数组
        children = new Trie[26];
        // 默认为不是最后一个字母
        isEnd = false;
    }

    public void insert(String word) {
        // 得到字典树根节点
        Trie node = this;
        // 去遍历待插入单词的字符集合
        for (char c : word.toCharArray()) {
            // 得到该字符在数组中的坐标(字母 'a' 对应索引 0,'b' 对应索引 1,以此类推)
            int index = c - 'a';
            // 如果正在遍历的该字母在上一个节点的数组坐标中没有记录,就新建一个字母节点在字典树中
            if (node.children[index] == null) {
                node.children[index] = new Trie();
            }
            // 每一次生成字母都移动指针到下一个字母节点
            node = node.children[index];
        }
        // 最后一个字母节点设置为最后一个字母
        node.isEnd = true;
    }

    public boolean search(String word) {
        // 返回检索到的最后一个字母节点
        Trie node = searchPrefix(word);
        // 只有当该单词在字典树中存在并且最后一个字母节点为最后一个字母,才返回 true
        return node!= null && node.isEnd;
    }

    public boolean startsWith(String prefix) {
        // 只要前缀匹配存在于字典树中就返回 true
        return searchPrefix(prefix)!= null;
    }

    // 前缀搜索和全文搜索都调用此方法,区别在于前缀搜索只要前缀匹配就返回 true,全文搜索则要匹配到最后一个字母才返回 true,所以这里返回的是最后一个字母节点
    public Trie searchPrefix(String word) {
        // 得到字典树根节点
        Trie node = this;
        // 开始验证字符串在字典树中是否存在
        for (char c : word.toCharArray()) {
            // 得到该字符在数组中的坐标(字母 'a' 对应索引 0,'b' 对应索引 1,以此类推)
            int index = c - 'a';
            // 如果该字符在数组中存在,就移动指针到下一个字母节点,直至到达最后一个待搜索的最后一个字母节点
            if (node.children[index]!= null) {
                node = node.children[index];
            } else {
                // 如果在此过程中没有找到待搜索的其中一个字母节点,就返回 null,代表该字母不存在于字典树中
                return null;
            }
        }
        // 没有问题,那就是到达了最后一个待搜索的最后一个字母节点,返回该节点(节点可能是最后一个字母节点也可能不是)
        return node;
    }
}

211. 添加与搜索单词 - 数据结构设计

java 复制代码
class WordDictionary {
    // 子节点数组,大小为 26,对应于每个小写字母('a' 到 'z')
    WordDictionary[] children;
    // 标志,表示该节点是否为某个单词的结尾
    boolean isEnd;

    // 构造函数,初始化子节点数组和 isEnd 标志
    public WordDictionary() {
        children = new WordDictionary[26]; // 初始化为 26 个子节点
        isEnd = false; // 初始化为非单词结尾
    }
    
    // 添加单词到字典
    public void addWord(String word) {
        WordDictionary node = this; // 从根节点开始
        // 遍历单词中的每个字符
        for (int i = 0; i < word.length(); i++) {
            int index = word.charAt(i) - 'a'; // 计算字符的索引(0-25)
            // 如果该字符对应的子节点尚未存在
            if (node.children[index] == null) {
                node.children[index] = new WordDictionary(); // 创建新的子节点
            }
            node = node.children[index]; // 移动到下一个节点
        }
        node.isEnd = true; // 标记当前节点为单词的结尾
    }

    // 查找单词,支持 '.' 通配符
    public boolean search(String word) {
        return search(this, word, 0); // 从当前节点开始查找
    }
    
    // 实际的递归查找方法
    public boolean search(WordDictionary node, String word, int start) {
        // 如果当前匹配到单词的结尾
        if (start == word.length()) {
            return node.isEnd; // 返回当前节点是否为单词结尾
        }
        
        char c = word.charAt(start); // 获取当前字符
        
        // 如果当前字符不是通配符 '.'
        if (c != '.') {
            WordDictionary item = node.children[c - 'a']; // 找到对应字符的子节点
            return item != null && search(item, word, start + 1); // 继续查找下一个字符
        }
        
        // 如果当前字符是通配符 '.',则检查所有可能的子节点
        for (int i = 0; i < 26; i++) {
            if (node.children[i] != null && search(node.children[i], word, start + 1)) {
                return true; // 找到匹配的路径,返回 true
            }
        }
        return false; // 未找到匹配的路径,返回 false
    }
}

/**
 * Your WordDictionary object will be instantiated and called as such:
 * WordDictionary obj = new WordDictionary(); // 创建字典对象
 * obj.addWord(word); // 添加单词
 * boolean param_2 = obj.search(word); // 查询单词
 */
相关推荐
GalaxyPokemon2 小时前
MySQL基础 [六] - 内置函数+复合查询+表的内连和外连
linux·运维·数据库·mysql·ubuntu
Linux运维老纪2 小时前
Linux 命令清单(Linux Command List)
linux·运维·服务器·数据库·mysql·云计算·运维开发
可观测性用观测云2 小时前
阿里巴巴 Druid 可观测性最佳实践
数据库
vim怎么退出3 小时前
30.两两交换链表中的节点
前端·leetcode
代码吐槽菌3 小时前
基于微信小程序的智慧乡村旅游服务平台【附源码】
java·开发语言·数据库·后端·微信小程序·小程序·毕业设计
喝醉酒的小白3 小时前
数据库如何确定或计算 LSN(日志序列号)
数据库
dengjiayue3 小时前
使用 redis 实现消息队列
数据库·redis·缓存
小羊学伽瓦3 小时前
【Redis】——最佳实践
数据库·redis·缓存
biubiubiu07064 小时前
Mysql
数据库·mysql
凌辰揽月4 小时前
眨眼睛查看密码工具类
java·开发语言·数据库