(经典字典树)leetcode中等211. 添加与搜索单词 - 数据结构设计

题目

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

实现词典类 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

这道题目跟普通的字典树相比多了一个’.'的匹配,这里我们可以理解为通配符,可以用递归的方法遇到普通字母就沿着它继续深搜,遇到通配符就可以沿着它当前节点的所有子节点深搜

代码部分

1.字典树的构建
#include <bits/stdc++.h>
#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;
	}	
};
2.插入单词

基本操作,逐个字符判断,没有就生成,单词最后的位置记得标记

    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;
    }
3.查询单词

这里是这道题目的核心部分,首先我们来写当前能做的事情,分为两种情况,一种是‘.’一种是正常的字符,'.'的时候我们需要对他的所有子节点进行深搜,结尾处的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 <bits/stdc++.h>
#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;
}







总结

这道题如果不会字典树那将是一个非常恐怖的存在,会了字典树之后可以说是很基础的一道题,所以这里用到的数据结构模板一定要非常熟悉,最好是达到倒背如流的样子,这样我们遇到一道题的时候,不用过多的思考数据结构的实现细节

猜你喜欢

转载自blog.csdn.net/weixin_46035615/article/details/124165111
今日推荐