添加与搜索单词 - 数据结构设计[中等]

一、题目

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

实现词典类WordDictionary
1、ordDictionary()初始化词典对象
2、void addWord(word)word添加到数据结构中,之后可以对它进行匹配
3、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"); // 返回 False
wordDictionary.search("bad"); // 返回 True
wordDictionary.search(".ad"); // 返回 True
wordDictionary.search("b.."); // 返回 True

1 <= word.length <= 25
addWord中的word由小写英文字母组成
search中的 word 由 ‘.’ 或小写英文字母组成
最多调用104addWordsearch

二、代码

字典树: 字典树(前缀树)是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。前缀树可以用O(∣S∣)的时间复杂度完成如下操作,其中∣S|是插入字符串或查询前缀的长度:
1、向字典树中插入字符串word
2、查询字符串word是否已经插入到字典树中。

思路和算法: 根据题意,WordDictionary类需要支持添加单词和搜索单词的操作,可以使用字典树实现。对于添加单词,将单词添加到字典树中即可。

对于搜索单词,从字典树的根结点开始搜索。由于待搜索的单词可能包含点号,因此在搜索过程中需要考虑点号的处理。对于当前字符是字母和点号的情况,分别按照如下方式处理:
1、如果当前字符是字母,则判断当前字符对应的子结点是否存在,如果子结点存在则移动到子结点,继续搜索下一个字符,如果子结点不存在则说明单词不存在,返回false
2、如果当前字符是点号,由于点号可以表示任何字母,因此需要对当前结点的所有非空子结点继续搜索下一个字符。

重复上述步骤,直到返回false或搜索完给定单词的最后一个字符。如果搜索完给定的单词的最后一个字符,则当搜索到的最后一个结点的isEndtrue时,给定的单词存在。特别地,当搜索到点号时,只要存在一个非空子结点可以搜索到给定的单词,即返回true

class WordDictionary {
    
    
    private Trie root;

    public WordDictionary() {
    
    
        root = new Trie();
    }
    
    public void addWord(String word) {
    
    
        root.insert(word);
    }
    
    public boolean search(String word) {
    
    
        return dfs(word, 0, root);
    }

    private boolean dfs(String word, int index, Trie node) {
    
    
        if (index == word.length()) {
    
    
            return node.isEnd();
        }
        char ch = word.charAt(index);
        if (Character.isLetter(ch)) {
    
    
            int childIndex = ch - 'a';
            Trie child = node.getChildren()[childIndex];
            if (child != null && dfs(word, index + 1, child)) {
    
    
                return true;
            }
        } else {
    
    
            for (int i = 0; i < 26; i++) {
    
    
                Trie child = node.getChildren()[i];
                if (child != null && dfs(word, index + 1, child)) {
    
    
                    return true;
                }
            }
        }
        return false;
    }
}

class Trie {
    
    
    private Trie[] children;
    private boolean isEnd;

    public Trie() {
    
    
        children = new Trie[26];
        isEnd = false;
    }
    
    public void insert(String word) {
    
    
        Trie node = this;
        for (int i = 0; i < word.length(); i++) {
    
    
            char ch = word.charAt(i);
            int index = ch - 'a';
            if (node.children[index] == null) {
    
    
                node.children[index] = new Trie();
            }
            node = node.children[index];
        }
        node.isEnd = true;
    }

    public Trie[] getChildren() {
    
    
        return children;
    }

    public boolean isEnd() {
    
    
        return isEnd;
    }
}

时间复杂度: 初始化为O(1),添加单词为O(∣S∣),搜索单词为O(∣Σ∣∣S∣),其中∣S∣是每次添加或搜索的单词的长度,Σ是字符集,这道题中的字符集为全部小写英语字母,∣Σ∣=26。最坏情况下,待搜索的单词中的每个字符都是点号,则每个字符都有∣Σ∣种可能。
空间复杂度: O(∣T∣⋅∣Σ∣),其中∣T∣是所有添加的单词的长度之和,Σ是字符集,这道题中的字符集为全部小写英语字母,∣Σ∣=26

猜你喜欢

转载自blog.csdn.net/zhengzhaoyang122/article/details/135210840
今日推荐