请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 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"); // return False
wordDictionary.search("bad"); // return True
wordDictionary.search(".ad"); // return True
wordDictionary.search("b.."); // return True
提示:
1 <= word.length <= 500
addWord
中的 word
由小写英文字母组成
search
中的 word
由 '.' 或小写英文字母组成
- 最多调用
50000
次 addWord
和 search
Related Topics
深度优先搜索设计字典树字符串 👍 403👎 0
【第一次写字典树】Java, 添加与搜索单词
第一次写字典树,之前也遇到过相关题目,知道有字典树这么个概念,但是根据学习计划,一直都还没接触。正好本周开始接触字符串相关算法了,才学习了KMP、Sunday、Shift And,正好遇到这题直接第一反应就是字典树。
在做题之前写去简单学习了下相关算法,按照本题题意,在没有`.`的时候写了第一版字典树算法
class WordDictionary {
TrieNode trieTree;
public WordDictionary() {
trieTree = new TrieNode('\u0000');
}
public void addWord(String word) {
if (null == word || word.length() < 1){
return;
}
int idx = -1;
TrieNode cur = trieTree;
while (++idx < word.length()){
if (!cur.children.containsKey(word.charAt(idx))){
cur.children.put(word.charAt(idx),new TrieNode(word.charAt(idx)));
}
cur = cur.children.get(word.charAt(idx));
}
cur.isTail = true;
}
public boolean search(String word) {
int idx = -1;
TrieNode cur = trieTree;
while (++idx < word.length()){
if (cur.children.containsKey(word.charAt(idx))){
cur = cur.children.get(word.charAt(idx));
}else{
return false;
}
}
return cur.isTail;
}
class TrieNode {
char value;
boolean isTail;
HashMap<Character,TrieNode> children;
public TrieNode(char value) {
this.value = value;
children = new HashMap<>();
}
}
}
写完了上面的,再来看这题,比一般匹配中多了一个`.`的可能,如果遇到`.`则表示可以是任意字符,那么相应的,最直观的作法,我们应当匹配下当前`TrieNode`下的`children`中的每一个节点。
在写代码之前
1. `children`结构一开始依旧是使用的`Hashmap`,虽然最终结果能跑通,但是性能上还是有点差距,后来看了下,对应的节点值只会是小写字母,也就是说范围限定死了,那么我们可以把`children`结构改为`TrieNode[]`数组,对应的key从0-25开始映射,这是一个小技巧,在部分情况下用数组代替`Hashmap`能有效提升不少性能,
2. 对于搜索部分,原本是`cur.children.get(word.charAt(idx))`,现在是不确定多少了,所以分情况判断,如果当前字符是`.`,则遍历children处理,如果不是则只处理对应的明确的那个节点。
3. 终止判断。
- 情况1:如果已经到了被搜索字符串结尾,而当前对应的节点不是一个结束节点,则返回false;
- 情况2:如果已经到了被搜索字符串结尾,且当前对应节点是一个结束节点,返回true;
- 情况3:在遍历过程中,寻找能和字符串匹配的下一个节点失败,返回false;
- 情况4:分支已经走到结束了了,而字符串遍历还没结束
那么,代码
class WordDictionary {
TrieNode trieTree;
public WordDictionary() {
trieTree = new TrieNode('\u0000');
}
public void addWord(String word) {
if (null == word || word.length() < 1){
return;
}
int idx = -1;
TrieNode cur = trieTree;
while (++idx < word.length()){
int key = word.charAt(idx)-'a';
if (cur.children[key] == null){
cur.children[key] = new TrieNode(word.charAt(idx));
}
cur = cur.children[key];
}
cur.isTail = true;
}
public boolean search(String word) {
return innerSearch(word,0,trieTree);
}
private boolean innerSearch(String word, int wordIdx, TrieNode startNode){
if (wordIdx == word.length() || null==startNode){
return null==startNode? false:startNode.isTail;
}
if (word.charAt(wordIdx)=='.'){
for (TrieNode child : startNode.children) {
if (innerSearch(word,wordIdx+1,child)){
return true;
}
}
}else if(innerSearch(word,wordIdx+1, startNode.children[word.charAt(wordIdx)-'a'])){
return true;
}
return false;
}
class TrieNode {
char value;
boolean isTail;
TrieNode[] children;
public TrieNode(char value) {
this.value = value;
children = new TrieNode[26];
}
}
}
跑了下结果,看起来勉强及格吧
解答成功:
执行耗时:40 ms,击败了67.98% 的Java用户
内存消耗:49 MB,击败了55.66% 的Java用户
今天第一次接触,有什么问题或者错误希望帮忙指出,感谢了