实现一个带有buildDict, 以及 search方法的魔法字典。
对于buildDict方法,你将被给定一串不重复的单词来构建一个字典。
对于search方法,你将被给定一个单词,并且判定能否只将这个单词中一个字母换成另一个字母,使得所形成的新单词存在于你构建的字典中。
示例 1:
Input: buildDict(["hello", "leetcode"]), Output: Null
Input: search("hello"), Output: False
Input: search("hhllo"), Output: True
Input: search("hell"), Output: False
Input: search("leetcoded"), Output: False
注意:
你可以假设所有输入都是小写字母 a-z。
为了便于竞赛,测试所用的数据量很小。你可以在竞赛结束后,考虑更高效的算法。
请记住重置MagicDictionary类中声明的类变量,因为静态/类变量会在多个测试用例中保留。 请参阅这里了解更多详情。
思路分析: 涉及到在字典中搜索单词的问题,一般前缀树的的结构能高效的解决问题。此题也是在单词组中搜索单词,蛋试需要搜索与word相差一个字母的单词,就是难度稍微增大了一点点。
关于前缀树的数据结构以及应用,请翻阅 LeetCode 前缀树及其运用
//前缀树的程序表示
class TrieNode {
public:
bool isWord;//当前节点为结尾是否是字符串
vector<TrieNode*> children;
TrieNode() : isWord(false), children(26, nullptr) {}
~TrieNode() {
for (TrieNode* child : children)
if (child) delete child;
}
};
class MagicDictionary {
private:
TrieNode *trieRoot;//构建的单词后缀树
//在树中插入一个单词的方法实现
void addWord(string &word) {
TrieNode *ptr = trieRoot;//扫描这棵树,将word插入
//将word的字符逐个插入
for (auto ch : word) {
if (ptr->children[ch - 'a'] == NULL) {
ptr->children[ch - 'a'] = new TrieNode();
}
ptr = ptr->children[ch - 'a'];
}
ptr->isWord = true;//标记为单词
}
//在nowTreePtr中搜索word[index],isMod代表的是是否使用了替换一个字母的机会
bool myFindWord(TrieNode *nowTreePtr, string &word, int index, bool isMod){
if (nowTreePtr == NULL){
return false;
}
if (word.size() == index){
//此时搜索完毕,必须保证nowTreePtr也到达了一个单词的尾端,并且替换一个字母的机会也使用了
return isMod && nowTreePtr->isWord;
}
else{
//搜索nowTreePtr的26个节点
for (int i = 0; i < 26; ++i){
if (nowTreePtr->children[i] != NULL){
if ('a' + i == word[index]){
//成功匹配,继续搜索下一个字母
if (myFindWord(nowTreePtr->children[i], word, index + 1, isMod)){
return true;
}
}
else if (isMod == false && myFindWord(nowTreePtr->children[i], word, index + 1, true)){
//如果'a' + i != word[index],则使用替换字母的机会(在此之前替换字母的机会是没有使用的,因为只能使用一次)
return true;
}
}
}
return false;
}
}
public:
/** Initialize your data structure here. */
MagicDictionary() {
trieRoot = new TrieNode();
}
/** Build a dictionary through a list of words */
void buildDict(vector<string> dict) {
//构建字典树
for (auto &word : dict){
addWord(word);
}
}
/** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
bool search(string word) {
return myFindWord(trieRoot, word, 0, false);
}
};
/**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary* obj = new MagicDictionary();
* obj->buildDict(dict);
* bool param_2 = obj->search(word);
*/