你还不会字典树吗,模板赶紧用起来吧!

438 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

说明

字典树:又称单词查找树Trie树,是一种树形结构,哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

字典树.png

字典树模板

public class WordTree {
    /**
     * 下一级节点
     */
    private WordTree[] next;
    /**
     * 单词结尾标识
     */
    private boolean isEnd;

    public WordTree() {
        this.next = new WordTree[26];
    }

    /**
     * 添加单词
     */
    public void addWrod(String word){
        WordTree wordTree = this;
        for(char w : word.toCharArray()){
            // 建立下级字符节点
            if (null == wordTree.next[w - 'a']){
                wordTree.next[w - 'a'] = new WordTree();
            }
            wordTree = wordTree.next[w - 'a'];
        }
        // 单词新增完成,修改标识
        wordTree.isEnd = true;
    }
    
    /**
     * 查找单词
     */
    public boolean search(String word){
        WordTree wordTree = this;
        // 遍历下级字符节点判断是否存在该字符
        for(char w : word.toCharArray()){
            if (null == wordTree.next[w - 'a']){
                return false;
            }
            wordTree = wordTree.next[w - 'a'];
        }
        
        // 返回结果
        return wordTree.isEnd;
    }
}

题目

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

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

实现词典类 WordDictionary

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

示例

输入:
["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"); // return False
wordDictionary.search("bad"); // return True
wordDictionary.search(".ad"); // return True
wordDictionary.search("b.."); // return True

提示

  • 1 <= word.length <= 500
  • addWord 中的 word 由小写英文字母组成
  • search 中的 word 由 '.' 或小写英文字母组成
  • 最多调用 50000addWordsearch

解题思路

看到单词以及查找字符串,那么很容易就可以想到通过字典树的方式来实现。稍有不同的是,在搜索字符串的过程中,我们需要针对'.'进行模糊查询,这个就得修改常规的字典树搜索逻辑,采用搜索算法来判断该字符串是否存在。

代码实现

class WordDictionary {
    /**
     * 下一级节点
     */
    private WordDictionary[] next;
    /**
     * 单词结尾标识
     */
    private boolean isEnd;

    public WordDictionary() {
        this.next = new WordDictionary[26];
    }
    
    /**
     * 添加单词
     */
    public void addWord(String word) {
        WordDictionary wordDictionary = this;
        for(char w : word.toCharArray()){
            if(null == wordDictionary.next[w - 'a']){
                wordDictionary.next[w - 'a'] = new WordDictionary();
            }
            wordDictionary = wordDictionary.next[w - 'a'];
        }
        wordDictionary.isEnd = true;
    }
    
    /**
     * 查找单词
     */
    public boolean search(String word) {
        // 由于该题需要进行模糊搜索,这里采用DFS的方式来判断
        return searchAll(word.toCharArray(), 0, this);
    }

    /**
     * @param word 字符串
     * @param index 索引
     * @param words 节点
     */
    public boolean searchAll(char[] word, int index, WordDictionary words){
        for(int i = index; i < word.length; ++i){
            // 模糊搜索需要遍历所有已存在的子节点
            if('.' == word[i]){
                boolean res = false;
                for(WordDictionary w : words.next){
                    if(w != null && !res){
                        res |= searchAll(word, i + 1, w);
                    }
                }
                return res;
            }
            // 子节点不存在,直接返回
            if(words.next[word[i] - 'a'] == null){
                return false;
            }else{
                // 字节点存在,则继续向下搜索
                words = words.next[word[i] - 'a'];
            }
        }
        // 返回结果
        return words.isEnd;
    }
}

复杂度分析

  • 时间复杂度:addWord操作为O(L)O(L), serach操作为O(LM)O(LM)
  • 空间复杂度:O(LM)O(LM)
  • L为字符串长度,M为子节点占用空间,本题为26

相似题目

212. 单词搜索 IIleetcode-cn.com/problems/wo…

208. 实现 Trie (前缀树)leetcode-cn.com/problems/im…

最后

文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!

如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!