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

1,问题描述

211. 添加与搜索单词 - 数据结构设计

难度:中等

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

实现词典类 WordDictionary

  • WordDictionary() 初始化词典对象
  • void addWord(word)word 添加到数据结构中,之后可以对它进行匹配
  • bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 falseword 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
输入:
["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 由 ‘.’ 或小写英文字母组成
  • 最多调用 104addWordsearch

2,初步思考

​ 使用其他方法会超时,如果使用字典树可以快速查找,这个也是通用的字典查询逻辑

3,代码处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package questions;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class _211添加与搜索单词数据结构设计 {
public static void main(String[] args) {
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
System.out.println(wordDictionary.search("pad"));
System.out.println(wordDictionary.search("bad"));
System.out.println(wordDictionary.search(".ad"));
System.out.println(wordDictionary.search("b.."));
}
}

class WordDictionary {
private List<TrieNode> trie;
private Set<String> trieSet;

public WordDictionary() {
trie = new ArrayList<>();
trieSet = new HashSet<>();
}

public void addWord(String word) {
if (!trieSet.contains(word)) {
trie.add(new TrieNode(word));
trieSet.add(word);
}
}

public boolean search(String word) {
for (TrieNode trieNode : trie) {
if (trieNode.match(word)) {
return true;
}
}
return false;
}
}

class TrieNode {
private String word;
private Integer len;

public TrieNode(String word) {
this.word = word;
this.len = word.length();
}

public boolean match(String otherWord) {
if (otherWord.length() != len) {// 长度不同,肯定不匹配
return false;
}
for (int i = 0; i < len; i++) {
if (otherWord.charAt(i) == '.') continue;
if (word.charAt(i) != otherWord.charAt(i)) {
return false;
}
}
return true;
}

public String getWord() {
return word;
}

public void setWord(String word) {
this.word = word;
}

public Integer getLen() {
return len;
}

public void setLen(Integer len) {
this.len = len;
}
}


// 必须要使用字典树才行
class WordDictionaryV2 {
private Trie root;

public WordDictionaryV2() {
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;
}
}