Given a pattern and a string s
, find if s
follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern
and a non-empty substring in s
.
Example 1:
Input: pattern = "abab", s = "redblueredblue" Output: true Explanation: One possible mapping is: 'a' -> "red" 'b' -> "blue"
Example 2:
Input: pattern = "aaaa", s = "asdasdasdasd" Output: true Explanation: One possible mapping is: 'a' -> "asd"
Example 3:
Input: pattern = "aabb", s = "xyzabcxzyabc" Output: false
Constraints:
1 <= pattern.length <= 20
1 <= s.length <= 50
pattern
and s
contain only lowercase English letters.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:
The brute force strategy for this puzzle involves trying every possible mapping between letters and parts of the string. It's like trying all the different ways to decode a secret message until you find the right one. If a mapping doesn't work, we simply discard it and try something else.
Here's how the algorithm would work step-by-step:
def word_pattern_match(pattern, input_string):
pattern_to_string = {}
string_to_pattern = {}
def backtrack(pattern_index, string_index):
# Base case: Both pattern and string are fully matched.
if pattern_index == len(pattern) and string_index == len(input_string):
return True
# If either pattern or string is exhausted while the other is not.
if pattern_index == len(pattern) or string_index == len(input_string):
return False
current_pattern_character = pattern[pattern_index]
# Try all possible substrings for the current pattern character.
for i in range(string_index + 1, len(input_string) + 1):
substring = input_string[string_index:i]
# Check if the pattern character already has a mapping.
if current_pattern_character in pattern_to_string:
# If the existing mapping doesn't match the current substring, skip.
if pattern_to_string[current_pattern_character] != substring:
continue
# Continue with the next character in the pattern.
if backtrack(pattern_index + 1, i):
return True
else:
# Ensure the substring is not already mapped to another pattern.
if substring in string_to_pattern:
continue
# Map the current pattern character to the current substring
pattern_to_string[current_pattern_character] = substring
string_to_pattern[substring] = current_pattern_character
# Attempt to match the rest of the pattern and string.
if backtrack(pattern_index + 1, i):
return True
# Backtrack: Remove the mapping to explore other possibilities.
del pattern_to_string[current_pattern_character]
del string_to_pattern[substring]
return False
return backtrack(0, 0)
The goal is to determine if a pattern of letters can be matched to segments of a string. We solve this using a backtracking approach, where we explore possible mappings between letters and string segments, pruning branches when they don't lead to a valid solution.
Here's how the algorithm would work step-by-step:
def word_pattern_match(pattern, input_string):
pattern_map = {}
string_map = {}
def backtrack(pattern_index, string_index):
# Base case: both pattern and string are exhausted.
if pattern_index == len(pattern) and string_index == len(input_string):
return True
# If either pattern or string is exhausted while the other is not, it's a mismatch.
if pattern_index == len(pattern) or string_index == len(input_string):
return False
current_pattern_char = pattern[pattern_index]
# Try all possible substrings for the current character.
for string_end_index in range(string_index + 1, len(input_string) + 1):
substring = input_string[string_index:string_end_index]
# Check if the mapping is consistent.
if current_pattern_char in pattern_map:
if pattern_map[current_pattern_char] != substring:
continue
elif substring in string_map:
continue
# Tentatively add the mapping and proceed recursively.
pattern_map[current_pattern_char] = substring
string_map[substring] = current_pattern_char
# Recursively check if the rest of the pattern matches the rest of the string.
if backtrack(pattern_index + 1, string_end_index):
return True
# Backtrack: remove the mapping to explore other possibilities.
del string_map[substring]
del pattern_map[current_pattern_char]
return False
return backtrack(0, 0)
Case | How to Handle |
---|---|
pattern is null or empty string | Return true if s is also empty; otherwise, return false. |
s is null or empty string | Return true if pattern is also empty; otherwise, return false. |
pattern length is greater than s length | Return false, as there's no way to map pattern characters to non-empty substrings. |
pattern and s have length 1 | Check if the single character matches; return true if they do, false if not. |
All characters in pattern are the same and all characters in s are the same | Determine if s can be divided into segments of equal characters to match length of the pattern. |
Two different pattern characters map to the same substring in 's' | The algorithm should detect conflicting mappings during the backtracking search and reject that branch. |
A single pattern character maps to different substrings in 's' | The algorithm should detect conflicting mappings during the backtracking search and reject that branch. |
The pattern contains repeated characters and s does not have corresponding repeating segments. | The backtracking algorithm will exhaust all possibilities and return false if no valid mapping is found. |