Stream of Characters - Complete Solution Guide
Stream of Characters is LeetCode problem 1032, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
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 array words . boolean qu
Detailed Explanation
The problem asks us to design a data structure that efficiently checks if a suffix of an incoming stream of characters matches any word in a given dictionary of words. The stream of characters arrives one character at a time, and after each character arrives, we need to determine if any suffix of the accumulated characters forms a word present in the dictionary. For example, if our dictionary contains ["abc", "xyz"] and the stream is 'a', 'x', 'y', 'z', then after receiving 'a' (stream is 'a') we return false, after 'x' (stream is 'ax') we return false, after 'y' (stream is 'axy') we return false, and after 'z' (stream is 'axyz') we return true because "xyz" is a suffix of "axyz" and is present in the dictionary.
Solution Approach
The solution utilizes a Trie data structure to store the reversed words from the input dictionary. A Trie is efficient for prefix-based searches, and reversing the words allows us to effectively search for suffixes. The solution also maintains a deque to store the recently seen characters from the stream. When a new character arrives, it is added to the deque. Then, the algorithm traverses the Trie, starting from the root and following the path dictated by the reversed deque contents. If a path exists in the Trie corresponding to a suffix of the deque and ends at a node marked as the end of a word, then the algorithm returns true. Otherwise, it returns false.
Step-by-Step Algorithm
- Step 1: Initialize the Trie: Build a Trie data structure from the given list of words. Reverse each word before inserting it into the Trie. Mark the end of each reversed word in the Trie with a special flag (e.g., '#').
- Step 2: Initialize the Character Stream History: Use a deque (double-ended queue) to keep track of the incoming characters from the stream. Set a maximum size for the deque equal to the length of the longest word in the dictionary.
- Step 3: Process each query character: When a new character arrives, add it to the right end of the deque. If the deque's size exceeds the maximum length, remove the oldest character from the left end (to maintain a window of relevant suffixes).
- Step 4: Search the Trie for a suffix match: Traverse the Trie, starting from the root, using the reversed characters in the deque. For each character, check if a corresponding branch exists in the Trie. If a character is not found in the Trie, it means no suffix starting with the current history can match, so return false.
- Step 5: Check for end-of-word: If, during the Trie traversal, you reach a node that is marked as the end of a word (i.e., the '#' flag is set), it means that the current suffix matches a word in the dictionary, so return true.
- Step 6: Return false if no match is found: If the Trie traversal completes without finding a matching suffix, return false.
Key Insights
- Insight 1: Using a Trie data structure allows for efficient prefix/suffix searching. Since we are checking for suffixes, we can build a Trie with the words reversed. This enables fast suffix lookup.
- Insight 2: Storing the incoming stream of characters in a queue (or deque) allows for quick access to the most recent characters, which form potential suffixes.
- Insight 3: The maximum length of the stream history needed is the length of the longest word in the dictionary. Any characters before that cannot contribute to a valid suffix match.
Complexity Analysis
Time Complexity: O(m)
Space Complexity: O(S)
Topics
This problem involves: Array, String, Design, Trie, Data Stream.
Companies
Asked at: Jane Street, Salesforce.