|
| 1 | +# 1032. Stream of Characters |
| 2 | + |
| 3 | +## Trie Solution |
| 4 | +- Run-time: O(N * Q) |
| 5 | +- Space: O(C) |
| 6 | +- N = Number of characters in stream |
| 7 | +- Q = Number of queries |
| 8 | +- C = Number of characters in word list |
| 9 | + |
| 10 | +When dealing with single characters, its worth considering the trie data structure. |
| 11 | +If we created a trie of the word list, we can figure out existence of words from the stream up to the recent query. |
| 12 | +However, you may notice that if we built the trie structure beginning from left to right, it would result in a slower run-time. |
| 13 | +This is because the new letter from the stream is at the right-most position while the trie structure starts at the left-most letter of each word in the word list. |
| 14 | +Instead of building it from the left to right, we can build the trie structure in reverse. |
| 15 | +That means, both the trie and the stream of letters would be traversed from the right to the left together. |
| 16 | +This can optimize for most outputs, however, there are still worst case inputs like a given word list of A's and a query of A's. |
| 17 | +This would result in an O(N * Q) run-time. |
| 18 | + |
| 19 | +``` |
| 20 | +from collections import defaultdict |
| 21 | +
|
| 22 | +class StreamChecker: |
| 23 | +
|
| 24 | + def __init__(self, words: List[str]): |
| 25 | + self.root = TrieNode.create_tries(words) |
| 26 | + self.stream = list() |
| 27 | +
|
| 28 | + def query(self, letter: str) -> bool: |
| 29 | + self.stream.append(letter) |
| 30 | + curr = self.root |
| 31 | + for ch in reversed(self.stream): |
| 32 | + if ch not in curr.next: |
| 33 | + return False |
| 34 | + curr = curr.next[ch] |
| 35 | + if curr.is_word: |
| 36 | + return True |
| 37 | + return False |
| 38 | +
|
| 39 | +class TrieNode(object): |
| 40 | +
|
| 41 | + def __init__(self): |
| 42 | + self.next = defaultdict(TrieNode) |
| 43 | + self.is_word = False |
| 44 | +
|
| 45 | + def __repr__(self): |
| 46 | + return '{} {}'.format([ch for ch in self.next], self.is_word) |
| 47 | +
|
| 48 | + @staticmethod |
| 49 | + def create_tries(words): |
| 50 | + root = TrieNode() |
| 51 | + for word in words: |
| 52 | + curr = root |
| 53 | + for ch in reversed(word): |
| 54 | + curr = curr.next[ch] |
| 55 | + curr.is_word = True |
| 56 | + return root |
| 57 | +``` |
0 commit comments