Given a list of strings words
and a string pattern
, return a list of words[i]
that match pattern
. You may return the answer in any order.
A word matches the pattern if there exists a permutation of letters p
so that after replacing every letter x
in the pattern with p(x)
, we get the desired word.
Recall that a permutation of letters is a bijection from letters to letters: every letter maps to another letter, and no two letters map to the same letter.
Example 1:
Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb" Output: ["mee","aqq"] Explanation: "mee" matches the pattern because there is a permutation {a -> m, b -> e, ...}. "ccc" does not match the pattern because {a -> c, b -> c, ...} is not a permutation, since a and b map to the same letter.
Example 2:
Input: words = ["a","b","c"], pattern = "a" Output: ["a","b","c"]
Constraints:
1 <= pattern.length <= 20
1 <= words.length <= 50
words[i].length == pattern.length
pattern
and words[i]
are 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 core idea of the brute force method here is to examine each word in a given list and see if it matches a given pattern. We systematically check every word against the pattern to find matches. If a word matches the pattern, we keep it.
Here's how the algorithm would work step-by-step:
def find_and_replace_pattern(words, pattern):
matching_words = []
for word in words:
if matches_pattern(word, pattern):
matching_words.append(word)
return matching_words
def matches_pattern(word, pattern):
if len(word) != len(pattern):
return False
word_to_pattern = {}
pattern_to_word = {}
for i in range(len(word)):
word_char = word[i]
pattern_char = pattern[i]
# Need to check existing mappings before creating new ones
if word_char in word_to_pattern:
if word_to_pattern[word_char] != pattern_char:
return False
if pattern_char in pattern_to_word:
if pattern_to_word[pattern_char] != word_char:
return False
# Ensure consistency: chars map only to one other char
if word_char not in word_to_pattern and pattern_char not in pattern_to_word:
word_to_pattern[word_char] = pattern_char
pattern_to_word[pattern_char] = word_char
return True
The core idea is to transform both the input word and the pattern into a normalized form. This normalized form reflects the relative order of characters rather than the specific characters themselves, allowing for direct comparison.
Here's how the algorithm would work step-by-step:
def find_and_replace_pattern(words, pattern):
matching_words = []
def normalize_word(word):
mapping = {}
normalized_pattern = []
counter = 1
# Use a map to keep track of the order that each letter appears
for letter in word:
if letter not in mapping:
mapping[letter] = counter
counter += 1
normalized_pattern.append(str(mapping[letter]))
return "".join(normalized_pattern)
normalized_pattern = normalize_word(pattern)
# Normalize the pattern for consistent comparisons
for word in words:
normalized_word = normalize_word(word)
# Compare normalized forms to see if they match.
if normalized_word == normalized_pattern:
matching_words.append(word)
# Only return the words that matched the pattern.
return matching_words
Case | How to Handle |
---|---|
Empty words array | Return an empty list immediately as there are no words to process. |
Empty pattern string | Return an empty list immediately as there is no pattern to match against. |
Null words array or pattern string | Throw an IllegalArgumentException or return an empty list to handle null input. |
Words array contains an empty string | The solution should handle this correctly by considering the empty string as a valid word to compare with the pattern. |
Words array contains very long strings | The solution's performance might degrade with very long strings, potentially requiring optimization if length becomes a constraint. |
Pattern string with repeating characters at the beginning or end (e.g., 'aabb') | The solution should correctly map the repeating pattern characters to the corresponding characters in the word. |
Word and pattern have different lengths | The solution should immediately determine that the word does not match the pattern and move on. |
Large number of words in the words array | The solution's efficiency depends on the number of words; consider optimizing for large datasets if performance becomes critical. |