leetcode211 design-add-and-search-words-data-structure
Leetcode 211. 添加与搜索单词 - 数据结构设计
Author: Carissa 🎀
Date: Dec.26 2023 🎄
1 题目
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary
:
WordDictionary()
初始化词典对象void addWord(word)
将word
添加到数据结构中,之后可以对它进行匹配bool search(word)
如果数据结构中存在字符串与word
匹配,则返回true
;否则,返回false
。word
中可能包含一些'.'
,每个.
都可以表示任何一个字母。
提示:
1 <= word.length <= 25
addWord
中的word
由小写英文字母组成search
中的word
由 ‘.’ 或小写英文字母组成- 最多调用
104
次addWord
和search
示例 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 思路
本题考点非常明确,即前缀树,但是我们应当注意到,这里在搜索时由于 ‘.’ 可以对应任意单词,还涉及到树的回溯搜索
==- 前缀树==
==- 回溯==
2.1 前缀树(Trie)
非常经典必须掌握的数据结构写法,在这里做简单回顾。
- 一个 TrieNode 结构应当包含以下部分:
- 字段:
val
: 当前节点的值childern
: 记录当前节点的子节点isEnd
: 记录当前节点是否是某个单词的结尾
- 方法(除了构造方法):
insert()
: 插入单词search()
: 搜索单词- 本题由于search方法有进一步回溯,可以放到题目的特定方法中去定义
- 字段:
- 尤其需要注意的是
children
的实现,一开始采用的是 Map 结构,导致代码异常复杂,对于字典树来说,只需要记录26个字母的情况,采用Node[26]
记录即可。
2.2 回溯
从根节点开始搜索,当返回
false
或单词的所有字符已全部搜索完成,则返回。对于每一个字符来说:
- 如果当前字符是字母,则判断当前字符是否能匹配本层节点,如果能则匹配下个字符,否则返回
false
- 如果当前字符是
.
, 则遍历所有的非空子节点
- 如果当前字符是字母,则判断当前字符是否能匹配本层节点,如果能则匹配下个字符,否则返回
需要注意的是:
- 判断字符
Character.isLetter()
可以使用
- 判断字符
回溯部分代码如下
1 | private boolean dfs(String word, int index, TreeNode node) { |
3 复杂度分析
时间复杂度:
初始化: O(1)
插入:O(∣S∣)
搜索:O(∣Σ∣∣S∣)
∣S∣ 是每次添加或搜索的单词的长度,Σ 是字符集,本题 ∣Σ∣=26。最坏情况下,待搜索的单词中的每个字符都是点号,则每个字符都有 ∣Σ∣种可能。
空间复杂度:O(∣Σ∣∣T∣)
∣T∣是所有添加的单词的长度之和
4 完整解法
1 | class WordDictionary { |