大家好,我是小魔龙,Unity3D软件工程师,VR、AR,虚拟仿真方向,不定时更新软件开发技巧,生活感悟,觉得有用记得一键三连哦。
一、题目
1、算法题目
“设计一个数据结构,支持添加新单词和查找字符串是否与任何以前添加的字符串匹配。”
2、题目描述
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary :
- WordDictionary() 初始化词典对象
- void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
- bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。
示例 1: 输入: ["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
示例 2:
二、解题
1、思路分析
这道题要我们实现一个词典类 WordDictionary,实现单词的添加和搜索。
词典类 WordDictionary可以是使用字典树实现,字典树(前缀树)是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。
字典树的空间复杂度为O(|S|),其中|S|是插入字符串或查询前缀的长度。
对于字典树的操作,插入就没什么好说的,主要是搜索。
对于搜索单词,从字典树根节点开始搜索,由于单词可能包含点号,在搜索的过程中需要处理点号:
- 如果当前字符是字母,则判断字符对应的子节点是否存在,存在则移动到子节点,继续搜索下一个字符,如果子节点不存在说明单词不存在,返回false。
- 如果当前字符是点号,由于点号可以表示任何字母,因此需要对当前节点的所有非空子节点继续搜索下一个字符。
重复上面的过程,直到返回false,或者搜索完单词的字符。
2、代码实现
代码参考:
class WordDictionary { private Trie root; public WordDictionary() { root = new Trie(); } public void addWord(String word) { root.insert(word); } public boolean search(String word) { return dfs(word, 0, root); } private boolean dfs(String word, int index, Trie node) { if (index == word.length()) { return node.isEnd(); } char ch = word.charAt(index); if (Character.isLetter(ch)) { int childIndex = ch - 'a'; Trie child = node.getChildren()[childIndex]; if (child != null && dfs(word, index + 1, child)) { return true; } } else { for (int i = 0; i < 26; i++) { Trie child = node.getChildren()[i]; if (child != null && dfs(word, index + 1, child)) { return true; } } } return false; } } class Trie { private Trie[] children; private boolean isEnd; public Trie() { children = new Trie[26]; isEnd = false; } public void insert(String word) { Trie node = this; for (int i = 0; i < word.length(); i++) { char ch = word.charAt(i); int index = ch - 'a'; if (node.children[index] == null) { node.children[index] = new Trie(); } node = node.children[index]; } node.isEnd = true; } public Trie[] getChildren() { return children; } public boolean isEnd() { return isEnd; } }
3、时间复杂度
时间复杂度:初始化为O(1),添加单词为O(|S|),搜索单词为O(|∑||S|)
其中|S|是每次添加或搜索的单词的长度,∑为字符集,这道题中的字符集为26个小写英语字母,|∑|=26。
空间复杂度:O(|T| · |∑|)
其中|T|是所有添加的单词的长度之和,∑为字符集,这道题中的字符集为26个小写英语字母,|∑|=26。
三、总结
总结一下:
- 根据给定字符串集合构建字典树
- 判断字典树终是否存在目标字符串
- 在字典树中找出目标字符串的最短前缀