请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 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”); // 返回 False
wordDictionary.search(“bad”); // 返回 True
wordDictionary.search(“.ad”); // 返回 True
wordDictionary.search(“b…”); // 返回 True
提示:
1 <= word.length <= 25
addWord 中的 word 由小写英文字母组成
search 中的 word 由 ‘.’ 或小写英文字母组成
最多调用 104 次 addWord 和 search
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-add-and-search-words-data-structure
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题目跟普通的字典树相比多了一个’.'的匹配,这里我们可以理解为通配符,可以用递归的方法遇到普通字母就沿着它继续深搜,遇到通配符就可以沿着它当前节点的所有子节点深搜
#include
#define MAXS 26
using namespace std;
struct TrieNode
{
TrieNode *child[MAXS];
bool isword;
TrieNode ():isword(false)
{
for(int i=0;i<MAXS;i++)
child[i]=NULL;
}
};
基本操作,逐个字符判断,没有就生成,单词最后的位置记得标记
void addWord(string word) {
TrieNode *t=&_root;
char *s=&word[0];
while(*s)
{
int pos=*s-'a';
if(!t->child[pos])
{
t->child[pos]=new TrieNode();
}
t=t->child[pos];
s++;
}
t->isword=true;
}
这里是这道题目的核心部分,首先我们来写当前能做的事情,分为两种情况,一种是‘.’一种是正常的字符,'.'的时候我们需要对他的所有子节点进行深搜,结尾处的return false是两种情况不满足条件时
//现在能做的事情
if(*s=='.')
{
for(int i=0;i<MAXS;i++)
{
if(t->child[i]&&search2(t->child[i],s+1))
return true;
}
}
else
{
int pos=*s-'a';
if(t->child[pos]&&search2(t->child[pos],s+1))
return true;
}
return false;
接下来就是出口,递归到什么时候我们要进行返回,一种时当前判断的字符不存在,这个我们已经隐藏在能做的事情里面了,然后就是判断到了字符串结尾的地方,我们应该判断最后一字母的位置是否是一个单词
//出口
if(*s=='\0')
{
return t->isword;
}
#include
#define MAXS 26
using namespace std;
struct TrieNode
{
TrieNode *child[MAXS];
bool isword;
TrieNode ():isword(false)
{
for(int i=0;i<MAXS;i++)
child[i]=NULL;
}
};
class WordDictionary {
public:
TrieNode _root;
WordDictionary() {
}
void addWord(string word) {
TrieNode *t=&_root;
char *s=&word[0];
while(*s)
{
int pos=*s-'a';
if(!t->child[pos])
{
t->child[pos]=new TrieNode();
}
t=t->child[pos];
s++;
}
t->isword=true;
}
bool search2(TrieNode *t,char *s)
{
//出口
if(*s=='\0')
{
return t->isword;
}
//现在能做的事情
if(*s=='.')
{
for(int i=0;i<MAXS;i++)
{
if(t->child[i]&&search2(t->child[i],s+1))
return true;
}
}
else
{
int pos=*s-'a';
if(t->child[pos]&&search2(t->child[pos],s+1))
return true;
}
return false;
}
bool search(string word) {
TrieNode *t=&_root;
char *s=&word[0];
return search2(t,s);
}
};
int main (void)
{
WordDictionary s;
vector<string> str={"abc","ab"};
for(int i=0;i<str.size();i++)
{
s.addWord(str[i]);
}
string s1=".b.";
cout<<s.search(s1);
return 0;
}
这道题如果不会字典树那将是一个非常恐怖的存在,会了字典树之后可以说是很基础的一道题,所以这里用到的数据结构模板一定要非常熟悉,最好是达到倒背如流的样子,这样我们遇到一道题的时候,不用过多的思考数据结构的实现细节