LeetCode 290: Word Pattern - All Solutions Explained
Problem Statement
The Word Pattern problem (LeetCode 290) is an easy-level hash table challenge where given a pattern
and a string s
, you need to determine if s
follows the same pattern. Here, "follow" means there is a bijection between letters in pattern and non-empty words in s
.
Constraints
- 1 ≤ pattern.length ≤ 300
- 1 ≤ s.length ≤ 3000
- pattern contains only lowercase English letters
- s contains lowercase English letters and spaces
- s does not contain leading or trailing spaces
- All words in s are separated by a single space
Example
Input: pattern = "abba", s = "dog cat cat dog"
Output: true
Input: pattern = "abba", s = "dog cat cat fish"
Output: false
Explanation of the Best Solution
This approach uses two hash maps to track the bidirectional mapping:
- Check Word Count:
- Split
s
into words - Verify number of words matches pattern length
- Create Mappings:
- char_to_word: pattern char → word
- word_to_char: word → pattern char
- Verify Consistency:
- For each pattern char and word pair:
- Check if existing mappings match current pair
- If conflict found, return false
- Result:
- Return true if all mappings are consistent
Step-by-Step Example
For pattern = "abba", s = "dog cat cat dog": 1. words = ["dog","cat","cat","dog"] 2. a → dog, dog → a 3. b → cat, cat → b 4. Second b matches existing cat mapping 5. Second a matches existing dog mapping → true
Python Code (Two Maps Solution)
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
words = s.split()
if len(pattern) != len(words):
return False
char_to_word = {}
word_to_char = {}
for char, word in zip(pattern, words):
if char in char_to_word:
if char_to_word[char] != word:
return False
else:
if word in word_to_char:
return False
char_to_word[char] = word
word_to_char[word] = char
return True
# Test cases
print(Solution().wordPattern("abba", "dog cat cat dog")) # True
print(Solution().wordPattern("abba", "dog cat cat fish")) # False
Complexity
- Time Complexity: O(n) - Single pass through pattern/words
- Space Complexity: O(m) - Where m is unique chars/words
- Optimizations: Early termination on mismatch
Why It's the Best
- Optimal O(n) time complexity
- Clear bidirectional mapping check
- Handles all edge cases
- Standard approach for pattern matching
Solution 2: Single Index Map (Alternative)
Explanation
This approach maps both pattern chars and words to their first occurrence indices:
- Check Lengths:
- Verify pattern and words have same length
- Create Index Map:
- Use dictionary to store first occurrence indices
- Compare Indices:
- For each char/word pair, check if their indices match
- Result:
- Return true if all indices match
Python Code (Index Map Solution)
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
words = s.split()
if len(pattern) != len(words):
return False
index_map = {}
for i, (char, word) in enumerate(zip(pattern, words)):
# Use separate keys for pattern chars and words
char_key = f'char_{char}'
word_key = f'word_{word}'
if char_key not in index_map and word_key not in index_map:
index_map[char_key] = i
index_map[word_key] = i
elif char_key not in index_map or word_key not in index_map:
return False
elif index_map[char_key] != index_map[word_key]:
return False
return True
# Test cases
print(Solution().wordPattern("abba", "dog cat cat dog")) # True
Complexity
- Time Complexity: O(n) - Single pass
- Space Complexity: O(m) - For index map
- Best for: When you want single map solution
Pros and Cons
- Pros: Single map simplifies implementation
- Cons: Slightly less intuitive than two maps
- Variation: Can use separate maps for chars/words
Solution 3: String Encoding (Clever Approach)
Explanation
This approach encodes both pattern and words as positional sequences:
- Generate Encodings:
- For pattern: sequence of first occurrence indices
- For words: same for word list
- Compare Encodings:
- Return true if encodings match
- Example:
- "abba" → [0,1,1,0]
- "dog cat cat dog" → [0,1,1,0]
Python Code (Encoding Solution)
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
words = s.split()
if len(pattern) != len(words):
return False
def encode(sequence):
encoding = []
mapping = {}
for i, item in enumerate(sequence):
if item not in mapping:
mapping[item] = i
encoding.append(mapping[item])
return encoding
return encode(pattern) == encode(words)
# Test cases
print(Solution().wordPattern("abba", "dog cat cat dog")) # True
Complexity
- Time Complexity: O(n) - Two passes (pattern + words)
- Space Complexity: O(m) - For encoding maps
- When to Use: When you prefer functional approach
Edge Cases to Consider
- Different length pattern and words → false
- All same pattern chars ("aaaa") with matching words
- All same pattern chars with different words → false
- All different pattern chars with same word → false
- Single character/word → true
Final Thoughts
- Two Maps Solution: Best for clarity and efficiency
- Index Map: Good single-map alternative
- Encoding Approach: Clever but less intuitive
- Key Insight: Bijection requires two-way consistency check
For further practice, try similar problems like Isomorphic Strings (LeetCode 205) or Word Pattern II (LeetCode 291).