原题说明
Implement the StreamChecker class as follows:
StreamChecker(words): Constructor, init the data structure with the given words.
query(letter): returns true if and only if for some k >= 1, the last k characters queried (in order from oldest to newest, including this letter just queried) spell one of the words in the given list.
Example
StreamChecker streamChecker = new StreamChecker([“cd”,”f”,”kl”]); // init the dictionary.
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
Note
1 <= words.length <= 2000
1 <= words[i].length <= 2000
- Words will only consist of lowercase English letters.
- Queries will only consist of lowercase English letters.
- The number of queries is at most 40000.
解题思路
题目要求输入一个字符串数组作为字典, 然后不断查询字符,如果最近的k
个字符构成一个完整的字典单词的话,返回true
,否则返回false
。
这个题目可以使用字典树(Trie
)求解。 对每个字符查询,当返回true
时,一定是一个完整的单词。值得注意的技巧是,反向查询可以节省很多开销。因为正向查询的话要保存很多上次访问到的节点,因为开始的地方可能会很多,所以这个Trie
可以反过来建, 这样每次查询的时候都可以从最后面开始查询起。
建Trie
的过程是对每个单词逆序插入Trie
, 从最后一个字符开始到第一个字符插入建立Trie
。
查询的时候,因为接受的是一个stream
,我们需要的stream
的长度不应该超过Trie
的最大深度。这样保证了我们的空间复杂度不会过大。
每次查询从stream
的最后一个字符开始向前查询,查到一个完整的单词就返回true
,否则就返回false
。
示例代码 (cpp)
1 | class TrieNode { |
示例代码 (java)
1 | class StreamChecker { |
示例代码 (python)
1 | from collections import deque |
复杂度分析
时间复杂度: O(d * (# of query))
空间复杂度: O(d * (# of dictionary))
d是dictionary中最长单词的长度。
归纳总结
我们在Youtube上更新了视频讲解,欢迎关注!