You are given an infinite stream of characters arriving one at a time. You are also given a string pattern. You need to find the first occurrence of the pattern in the stream.
Implement the StreamRanker class:
StreamRanker(String pattern) Initializes the StreamRanker object with the pattern string.void add(char c) Adds a new character c to the stream.int getRank() Return the number of characters read from the stream so far. Return -1 if pattern was not found. Return (index of the last char of pattern) + 1 if pattern was found.Example 1:
Input
["StreamRanker", "add", "getRank", "add", "getRank", "add", "getRank", "add", "getRank", "add", "getRank", "add", "getRank", "add", "getRank"]
[["abab"], ["a"], [], ["b"], [], ["a"], [], ["b"], [], ["a"], [], ["b"], [], ["b"], []]
Output
[null, null, -1, null, -1, null, -1, null, 4, null, -1, null, 4, null, -1]
Explanation
StreamRanker streamRanker = new StreamRanker("abab");
streamRanker.add("a"); // stream = "a"
streamRanker.getRank(); // return -1
streamRanker.add("b"); // stream = "ab"
streamRanker.getRank(); // return -1
streamRanker.add("a"); // stream = "aba"
streamRanker.getRank(); // return -1
streamRanker.add("b"); // stream = "abab"
streamRanker.getRank(); // return 4, because "abab" is found at index 0
streamRanker.add("a"); // stream = "ababa"
streamRanker.getRank(); // return -1, because we want the first occurence
streamRanker.add("b"); // stream = "ababab"
streamRanker.getRank(); // return 4, because "abab" is found at index 0
streamRanker.add("b"); // stream = "abababb"
streamRanker.getRank(); // return -1
Constraints:
1 <= pattern.length <= 1000pattern consists of only lowercase English letters.c is a lowercase English letter.105 calls will be made to add and getRank.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine we're searching for a secret message hidden within a long, never-ending flow of characters. The brute force method means we'll meticulously examine every possible snippet of the flow to see if it matches the secret message. We'll essentially try out all combinations, one by one, until we find it.
Here's how the algorithm would work step-by-step:
def find_pattern_brute_force(stream, pattern):
stream_length = len(stream)
pattern_length = len(pattern)
for start_index in range(stream_length):
# Iterate through all possible starting positions
for end_index in range(start_index + 1, stream_length + 1):
# Check all possible lengths of substrings starting from current position
substring = stream[start_index:end_index]
if len(substring) == pattern_length:
# Only check if the substring is the same length as the pattern
if substring == pattern:
# Return true if substring matches pattern
return True
return FalseThe key to solving this problem efficiently is to avoid storing the entire infinite stream and to use a finite state machine based on the pattern. We use the pattern to define the states and transitions, allowing us to check if the pattern exists in the stream incrementally.
Here's how the algorithm would work step-by-step:
def find_pattern_in_stream(stream, pattern):
pattern_length = len(pattern)
current_state = 0
for element in stream:
# Check if the current element matches the expected pattern element.
if element == pattern[current_state]:
current_state += 1
# If we've reached the end of the pattern, report it.
if current_state == pattern_length:
print("Pattern found!")
current_state = 0 # Reset to start, search again
# If no match, start looking for the pattern from beginning
else:
current_state = 0| Case | How to Handle |
|---|---|
| Null or empty pattern string | Return an empty list or an appropriate error code to indicate no pattern to search for. |
| Null or empty stream of characters | Return an empty list or an appropriate error code to indicate no input stream to search within. |
| Pattern longer than the available stream | Return an empty list if the stream is shorter than the pattern, as a match is impossible. |
| Pattern containing special characters (e.g., Unicode, control characters) | Ensure the comparison logic handles these characters correctly, especially if using language-specific string functions or regular expressions. |
| Extremely long pattern and stream (scalability) | Consider using an efficient string matching algorithm like Knuth-Morris-Pratt (KMP) or Boyer-Moore to avoid quadratic time complexity. |
| Overlapping patterns within the stream (e.g., pattern 'abab' in stream 'abababab') | Ensure the algorithm correctly identifies all occurrences of the pattern, even if they overlap. |
| Pattern contains repeated characters (e.g., 'aaa') | KMP algorithm needs to handle building the correct LPS array for repeated character patterns. |
| No match found in the stream | Return an empty list to indicate that the pattern was not found. |