leetcode-211. 添加与搜索单词 - 数据结构设计
leetcode-211. 添加与搜索单词 - 数据结构设计
题目:
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary :
- WordDictionary() 初始化词典对象
- void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
- bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。
思路:
-
本题直接将所有的单词存入数组中,在查找时遍历所有单词,但这样代码查找效率低下,可能会超时,因此我们可以对单词根据代码根据长度进行分类,存储到map<int,vector<string>>的数据结构中,map的key为长度,value为对应长度的单词,插入单词时先计算单词长度再插入对应的数组中,查找时,直接根据单词长度找到对应的集合,遍历集合中的所有单词,再进行逐字符匹配,如果是'.'则跳过该次,如果有单词匹配成功则返回true。
-
本题也可以通过前缀树解决,因为单词只有26个,因此构建的字典树为26叉树,并置一个标志isEnd记录此字母是否为单词末尾
数据结构:
class TrieNode{ public: //存储孩子节点 vector<TrieNode*> child; //末尾标志 bool isEnd; TrieNode(){ //初始化孩子节点 child=vector<TrieNode*>{26,nullptr}; //默认置为false,插入时将最后一个字母的标志置为true isEnd=false; }; };
插入元素时,通过遍历将单词合并到前缀树
查找元素时,
- 如果遍历到单词末尾,则意味着单词匹配成功,返回true
- 如果单当前字母为a-z,则递归判断trie->child[word[i]-'a']和word[i+1:]的查询结果
- 如果遍历的当前字母为'.',则需要对每个子节点都进行一次递归查找
Code
- map集合
class WordDictionary {
public:
map<int,vector<string>> m;
WordDictionary() {
}
void addWord(string word) {
if(m.count(word.size())==0){
vector<string> cur={word};
m[word.size()]=cur;
}
else{
m[word.size()].push_back(word);
}
}
bool search(string word) {
int len=word.size();
if(m.count(len)==0){
return false;
}
for(auto item:m[word.size()]){
bool have=true;
for(int i=0;i<len;i++){
if(word[i]!='.' && word[i]!=item[i]){
have=false;
}
}
if(have){
return true;
}
}
return false;
}
};
- 前缀树
class TrieNode{
public:
vector<TrieNode*> child;
bool isEnd;
TrieNode(){
child=vector<TrieNode*>{26,nullptr};
isEnd=false;
};
};
class WordDictionary {
public:
TrieNode* root;
WordDictionary() {
root=new TrieNode();
}
void addWord(string word) {
TrieNode* cur=root;
for(int i=0;i<word.size();i++){
if(cur->child[word[i]-'a']==nullptr){
cur->child[word[i]-'a']=new TrieNode();
}
cur=cur->child[word[i]-'a'];
}
//末尾标志置位true
cur->isEnd=true;
};
bool search(string word) {
TrieNode* cur=root;
//递归查询
return dfs(cur,0,word);
};
bool dfs(TrieNode* root,int inx,string word){
//查找到末尾
if(inx==word.size()){
return root->isEnd;
};
//遇到'.'需要将26个字母都遍历一次
if(word[inx]=='.'){
for(int i=0;i<26;i++){
if(root->child[i]!=nullptr && dfs(root->child[i],inx+1,word)){
return true;
}
}
return false;
}
else{
if(root->child[word[inx]-'a']!=nullptr && dfs(root->child[word[inx]-'a'],inx+1,word)){
return true;
}
return false;
};
};
};