英文原文
Design an algorithm that accepts a stream of characters and checks if a suffix of these characters is a string of a given array of strings words
.
For example, if words = ["abc", "xyz"]
and the stream added the four characters (one by one) 'a'
, 'x'
, 'y'
, and 'z'
, your algorithm should detect that the suffix "xyz"
of the characters "axyz"
matches "xyz"
from words
.
Implement the StreamChecker
class:
StreamChecker(String[] words)
Initializes the object with the strings arraywords
.boolean query(char letter)
Accepts a new character from the stream and returnstrue
if any non-empty suffix from the stream forms a word that is inwords
.
Example 1:
Input ["StreamChecker", "query", "query", "query", "query", "query", "query", "query", "query", "query", "query", "query", "query"] [[["cd", "f", "kl"]], ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"]] Output [null, false, false, false, true, false, true, false, false, false, false, false, true] Explanation StreamChecker streamChecker = new StreamChecker(["cd", "f", "kl"]); streamChecker.query("a"); // return False streamChecker.query("b"); // return False streamChecker.query("c"); // return False streamChecker.query("d"); // return True, because 'cd' is in the wordlist streamChecker.query("e"); // return False streamChecker.query("f"); // return True, because 'f' is in the wordlist streamChecker.query("g"); // return False streamChecker.query("h"); // return False streamChecker.query("i"); // return False streamChecker.query("j"); // return False streamChecker.query("k"); // return False streamChecker.query("l"); // return True, because 'kl' is in the wordlist
Constraints:
1 <= words.length <= 2000
1 <= words[i].length <= 2000
words[i]
consists of lowercase English letters.letter
is a lowercase English letter.- At most
4 * 104
calls will be made to query.
中文题目
按下述要求实现 StreamChecker
类:
StreamChecker(words)
:构造函数,用给定的字词初始化数据结构。query(letter)
:如果存在某些k >= 1
,可以用查询的最后k
个字符(按从旧到新顺序,包括刚刚查询的字母)拼写出给定字词表中的某一字词时,返回true
。否则,返回false
。
示例:
StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // 初始化字典 streamChecker.query('a'); // 返回 false streamChecker.query('b'); // 返回 false streamChecker.query('c'); // 返回 false streamChecker.query('d'); // 返回 true,因为 'cd' 在字词表中 streamChecker.query('e'); // 返回 false streamChecker.query('f'); // 返回 true,因为 'f' 在字词表中 streamChecker.query('g'); // 返回 false streamChecker.query('h'); // 返回 false streamChecker.query('i'); // 返回 false streamChecker.query('j'); // 返回 false streamChecker.query('k'); // 返回 false streamChecker.query('l'); // 返回 true,因为 'kl' 在字词表中。
提示:
1 <= words.length <= 2000
1 <= words[i].length <= 2000
- 字词只包含小写英文字母。
- 待查项只包含小写英文字母。
- 待查项最多 40000 个。
通过代码
高赞题解
题目地址(1032. 字符流)
https://leetcode-cn.com/problems/stream-of-characters/
题目描述
按下述要求实现 StreamChecker 类:
StreamChecker(words):构造函数,用给定的字词初始化数据结构。
query(letter):如果存在某些 k >= 1,可以用查询的最后 k个字符(按从旧到新顺序,包括刚刚查询的字母)拼写出给定字词表中的某一字词时,返回 true。否则,返回 false。
示例:
StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // 初始化字典
streamChecker.query('a'); // 返回 false
streamChecker.query('b'); // 返回 false
streamChecker.query('c'); // 返回 false
streamChecker.query('d'); // 返回 true,因为 'cd' 在字词表中
streamChecker.query('e'); // 返回 false
streamChecker.query('f'); // 返回 true,因为 'f' 在字词表中
streamChecker.query('g'); // 返回 false
streamChecker.query('h'); // 返回 false
streamChecker.query('i'); // 返回 false
streamChecker.query('j'); // 返回 false
streamChecker.query('k'); // 返回 false
streamChecker.query('l'); // 返回 true,因为 'kl' 在字词表中。
提示:
1 <= words.length <= 2000
1 <= words[i].length <= 2000
字词只包含小写英文字母。
待查项只包含小写英文字母。
待查项最多 40000 个。
前置知识
- 前缀树
思路
题目要求按从旧到新顺序
查询,因此可以将从旧到新的 query 存起来形成一个单词 stream。
比如:
streamChecker.query("a"); // stream: a
streamChecker.query("b"); // stream:ba
streamChecker.query("c"); // stream:cba
这里有两个小的点需要注意:
- 如果用数组来存储, 由于每次都往数组头部插入一个元素,因此每次 query 操作的时间复杂度为 $O(N)$,其中 $N$ 为截止当前执行 query 的次数,我们可以使用双端队列进行优化。
- 由于不必 query 形成的查询全部命中。比如 stream 为 cba 的时候,找到单词 c, bc, abc 都是可以的。如果是找到 c,cb,cba 比较好吧,现在是反的。其实我们可以反序插入是,类似的技巧在211.add-and-search-word-data-structure-design 也有用到。
之后我们用拼接的单词在 words 中查询即可, 最简单的方式当然是每次 query 都去扫描一次,这种方式毫无疑问会超时。
我们可以采用构建 Trie 的形式,即已空间环时间, 其代码和常规的 Trie 类似,只需要将 search(word) 函数做一个简单修改即可,我们不需要检查整个 word 是否存在, 而已 word 的前缀存在即可。
提示:可以通过对 words 去重,来用空间换区时间。
具体算法:
- init 中 构建 Trie 和 双端队列 stream
- query 时,往 stream 的左边 append 即可。
- 调用 Trie 的 search(和常规的 search 稍有不同, 我上面已经讲了)
核心代码(Python):
class StreamChecker:
def __init__(self, words: List[str]):
self.trie = Trie()
self.stream = deque([])
for word in set(words):
self.trie.insert(word[::-1])
def query(self, letter: str) -> bool:
self.stream.appendleft(letter)
return self.trie.search(self.stream)
关键点解析
- 前缀树模板
- 倒序插入
代码
- 语言支持: Python
Python Code:
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.Trie = {}
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
curr = self.Trie
for w in word:
if w not in curr:
curr[w] = {}
curr = curr[w]
curr['#'] = 1
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
curr = self.Trie
for w in word:
if w not in curr:
return False
if "#" in curr[w]:
return True
curr = curr[w]
return False
class StreamChecker:
def __init__(self, words: List[str]):
self.trie = Trie()
self.stream = deque([])
for word in set(words):
self.trie.insert(word[::-1])
def query(self, letter: str) -> bool:
self.stream.appendleft(letter)
return self.trie.search(self.stream)
相关题目
- 0208.implement-trie-prefix-tree
- 0211.add-and-search-word-data-structure-design
- 0212.word-search-ii
- 0472.concatenated-words
- 0820.short-encoding-of-words
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
2725 | 6758 | 40.3% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|