Skip to content

Commit 4e2469e

Browse files
committed
feat: add solutions lc problem: No.1032
No.1032.Stream of Characters
1 parent 6367ed8 commit 4e2469e

File tree

6 files changed

+644
-0
lines changed

6 files changed

+644
-0
lines changed

solution/1000-1099/1032.Stream of Characters/README.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,246 @@ streamChecker.query("l"); // 返回 True ,因为 'kl' 在 words 中
6060

6161
<!-- 这里可写通用的实现逻辑 -->
6262

63+
**方法一:前缀树**
64+
65+
构建前缀树,每个节点保存一个字符,从根节点开始,每次遍历到一个字符,就将其加入到当前节点的子节点中,同时将当前节点的 `isEnd` 标记为 `true`。当遍历到字符串的末尾时,将当前节点的 `isEnd` 标记为 `true`
66+
67+
查询时,从根节点开始,每次遍历到一个字符,就将其加入到当前节点的子节点中,同时将当前节点的 `isEnd` 标记为 `true`。当遍历到字符串的末尾时,将当前节点的 `isEnd` 标记为 `true`
68+
69+
对于本题,我们采用**字符串的反序**来构建前缀树,这样在查询时,只需要从根节点开始,遍历到当前字符即可,不需要遍历到字符串的末尾。
70+
71+
初始化前缀树的时间复杂度为 $O(n)$,其中 $n$ 为 `words` 所有字符总数。单次查询的时间复杂度为 $O(m)$,其中 $m$ 为 `words` 中单词的最大长度。
72+
6373
<!-- tabs:start -->
6474

6575
### **Python3**
6676

6777
<!-- 这里可写当前语言的特殊实现逻辑 -->
6878

6979
```python
80+
class Trie:
81+
def __init__(self):
82+
self.children = [None] * 26
83+
self.is_end = False
84+
85+
def insert(self, w):
86+
node = self
87+
for c in w[::-1]:
88+
idx = ord(c) - ord('a')
89+
if node.children[idx] is None:
90+
node.children[idx] = Trie()
91+
node = node.children[idx]
92+
node.is_end = True
93+
94+
def search(self, w):
95+
node = self
96+
for c in w[::-1]:
97+
idx = ord(c) - ord('a')
98+
if node.children[idx] is None:
99+
return False
100+
node = node.children[idx]
101+
if node.is_end:
102+
return True
103+
return False
104+
105+
106+
class StreamChecker:
70107

108+
def __init__(self, words: List[str]):
109+
self.trie = Trie()
110+
self.s = []
111+
for w in words:
112+
self.trie.insert(w)
113+
114+
def query(self, letter: str) -> bool:
115+
self.s.append(letter)
116+
return self.trie.search(self.s[-201:])
117+
118+
# Your StreamChecker object will be instantiated and called as such:
119+
# obj = StreamChecker(words)
120+
# param_1 = obj.query(letter)
71121
```
72122

73123
### **Java**
74124

75125
<!-- 这里可写当前语言的特殊实现逻辑 -->
76126

77127
```java
128+
class Trie {
129+
Trie[] children = new Trie[26];
130+
boolean isEnd = false;
131+
132+
public void insert(String w) {
133+
Trie node = this;
134+
for (int i = w.length() - 1; i >= 0; --i) {
135+
int idx = w.charAt(i) - 'a';
136+
if (node.children[idx] == null) {
137+
node.children[idx] = new Trie();
138+
}
139+
node = node.children[idx];
140+
}
141+
node.isEnd = true;
142+
}
143+
144+
public boolean query(StringBuilder s) {
145+
Trie node = this;
146+
for (int i = s.length() - 1, j = 0; i >= 0 && j < 201; --i, ++j) {
147+
int idx = s.charAt(i) - 'a';
148+
if (node.children[idx] == null) {
149+
return false;
150+
}
151+
node = node.children[idx];
152+
if (node.isEnd) {
153+
return true;
154+
}
155+
}
156+
return false;
157+
}
158+
}
159+
160+
class StreamChecker {
161+
private StringBuilder sb = new StringBuilder();
162+
private Trie trie = new Trie();
163+
164+
public StreamChecker(String[] words) {
165+
for (String w : words) {
166+
trie.insert(w);
167+
}
168+
}
169+
170+
public boolean query(char letter) {
171+
sb.append(letter);
172+
return trie.query(sb);
173+
}
174+
}
175+
176+
/**
177+
* Your StreamChecker object will be instantiated and called as such:
178+
* StreamChecker obj = new StreamChecker(words);
179+
* boolean param_1 = obj.query(letter);
180+
*/
181+
```
182+
183+
### **C++**
184+
185+
```cpp
186+
class Trie {
187+
public:
188+
vector<Trie*> children;
189+
bool isEnd;
190+
191+
Trie()
192+
: children(26)
193+
, isEnd(false) { }
194+
195+
void insert(string& w) {
196+
Trie* node = this;
197+
reverse(w.begin(), w.end());
198+
for (char c : w) {
199+
int idx = c - 'a';
200+
if (!node->children[idx]) node->children[idx] = new Trie();
201+
node = node->children[idx];
202+
}
203+
node->isEnd = true;
204+
}
205+
206+
bool search(string& w) {
207+
Trie* node = this;
208+
for (int i = w.size() - 1, j = 0; ~i && j < 201; --i, ++j) {
209+
int idx = w[i] - 'a';
210+
if (!node->children[idx]) return false;
211+
node = node->children[idx];
212+
if (node->isEnd) return true;
213+
}
214+
return false;
215+
}
216+
};
217+
218+
class StreamChecker {
219+
public:
220+
Trie* trie = new Trie();
221+
string s;
222+
StreamChecker(vector<string>& words) {
223+
for (string& w : words) {
224+
trie->insert(w);
225+
}
226+
}
227+
228+
bool query(char letter) {
229+
s += letter;
230+
return trie->search(s);
231+
}
232+
};
233+
234+
/**
235+
* Your StreamChecker object will be instantiated and called as such:
236+
* StreamChecker* obj = new StreamChecker(words);
237+
* bool param_1 = obj->query(letter);
238+
*/
239+
```
240+
241+
### **Go**
242+
243+
```go
244+
type Trie struct {
245+
children [26]*Trie
246+
isEnd bool
247+
}
248+
249+
func newTrie() Trie {
250+
return Trie{}
251+
}
252+
253+
func (this *Trie) Insert(word string) {
254+
node := this
255+
for i := len(word) - 1; i >= 0; i-- {
256+
idx := word[i] - 'a'
257+
if node.children[idx] == nil {
258+
node.children[idx] = &Trie{}
259+
}
260+
node = node.children[idx]
261+
}
262+
node.isEnd = true
263+
}
264+
265+
func (this *Trie) Search(word []byte) bool {
266+
node := this
267+
for i, j := len(word)-1, 0; i >= 0 && j < 201; i, j = i-1, j+1 {
268+
idx := word[i] - 'a'
269+
if node.children[idx] == nil {
270+
return false
271+
}
272+
node = node.children[idx]
273+
if node.isEnd {
274+
return true
275+
}
276+
}
277+
return false
278+
}
279+
280+
type StreamChecker struct {
281+
trie Trie
282+
s []byte
283+
}
284+
285+
func Constructor(words []string) StreamChecker {
286+
trie := newTrie()
287+
for _, w := range words {
288+
trie.Insert(w)
289+
}
290+
return StreamChecker{trie, []byte{}}
291+
}
292+
293+
func (this *StreamChecker) Query(letter byte) bool {
294+
this.s = append(this.s, letter)
295+
return this.trie.Search(this.s)
296+
}
78297
298+
/**
299+
* Your StreamChecker object will be instantiated and called as such:
300+
* obj := Constructor(words);
301+
* param_1 := obj.Query(letter);
302+
*/
79303
```
80304

81305
### **...**

0 commit comments

Comments
 (0)