题目
题目来源:力扣(LeetCode)
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary :
WordDictionary() 初始化词典对象
void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。
示例:
输入:
[“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
思路分析
根据题意,WordDictionary 类需要支持添加单词和搜索单词的操作,可以使用字典树实现。
对于添加单词,将单词添加到字典树中即可。
对于搜索单词,从字典树的根结点开始搜索。由于待搜索的单词可能包含点号,因此在搜索过程中需要考虑点号的处理。对于当前字符是字母和点号的情况,分别按照如下方式处理:
如果当前字符是字母,则判断当前字符对应的子结点是否存在,如果子结点存在则移动到子结点,继续搜索下一个字符,如果子结点不存在则说明单词不存在,返回 false;
如果当前字符是点号,由于点号可以表示任何字母,因此需要对当前结点的所有非空子结点继续搜索下一个字符。
重复上述步骤,直到返回 false 或搜索完给定单词的最后一个字符。
如果搜索完给定的单词的最后一个字符,则当搜索到的最后一个结点的isEnd 为 true 时,给定的单词存在。
特别地,当搜索到点号时,只要存在一个非空子结点可以搜索到给定的单词,即返回 true。
// 字典树
class TrieNode {
constructor() {
this.children = new Array(26).fill(0);
this.isEnd = false;
}
insert(word) {
let node = this;
for (let i = 0; i < word.length; i++) {
const ch = word[i];
// 计算当前字符的索引
const index = ch.charCodeAt() - 'a'.charCodeAt();
// 若索引位置还没有单词,则在此新建字典树
if (node.children[index] === 0) node.children[index] = new
TrieNode();
node = node.children[index];
}
// 结尾标记单词结束了
node.isEnd = true;
}
getChildren() {
return this.children;
}
isEnd() {
return this.isEnd;
}
}
class WordDictionary {
constructor() {
this.trieRoot = new TrieNode();
}
addWord(word) {
this.trieRoot.insert(word);
}
search(word) {
const dfs = (index, node) => {
// 若索引长度等于单词数,说明遍历完了,返回isEnd
if (index === word.length) return node.isEnd;
const ch = word[index];
if (ch !== '.') {
// 当前字符是字母,必须保证一致
const child = node.children[ch.charCodeAt() - 'a'.charCodeAt()];
if (child && dfs(index + 1, child)) return true;
} else {
// 当前字符是点,点可以代表任何字符
// 只要有一个子节点是true即可
for (const child of node.children) {
if (child && dfs(index + 1, child)) return true;
}
}
// 字符不存在,返回false
return false;
};
return dfs(0, this.trieRoot);
}
}
/**
* Your WordDictionary object will be instantiated and called as such:
* var obj = new WordDictionary()
* obj.addWord(word)
* var param_2 = obj.search(word)
*/