290. Word Pattern
On LeetCode ->Reformulated question¶
Given a pattern like "abba" and a space-separated string like "dog cat cat dog", return True iff there is a one-to-one mapping between pattern letters and words.
Example:
Key Trick¶
Check both directions of the mapping.
- letter -> word must stay consistent
- word -> letter must also stay consistent
Without the reverse check, two letters could incorrectly map to the same word.
Trap¶
Common mistakes:
- Only storing
letter -> wordand forgetting bijection. - Forgetting to first check that number of letters equals number of words.
- Using
if mapping.get(ch)style checks that depend on truthiness instead of key existence. - Repeatedly using
word in mapping.values(), which is less clean and turns lookup into linear time.
Why This Question Is Interesting¶
It looks like simple string parsing, but the real idea is enforcing a bijection.
It is a small hash map problem that tests:
- modeling constraints correctly
- edge cases
- clean dictionary usage
Solve the Problem with Idiomatic Python¶
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
words = s.split()
# Full match requires same number of items.
if len(pattern) != len(words):
return False
char_to_word = {}
word_to_char = {}
for ch, word in zip(pattern, words):
# If either side already exists, both must match.
if ch in char_to_word:
if char_to_word[ch] != word:
return False
elif word in word_to_char:
return False
else:
char_to_word[ch] = word
word_to_char[word] = ch
return True
Optional compact Pythonic variant:
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
words = s.split()
return (
len(pattern) == len(words)
and len(set(pattern)) == len(set(words)) == len(set(zip(pattern, words)))
)
Pytest Test¶
import pytest
@pytest.mark.parametrize(
("pattern", "s", "expected"),
[
("abba", "dog cat cat dog", True),
("abba", "dog cat cat fish", False),
("aaaa", "dog cat cat dog", False),
("abba", "dog dog dog dog", False),
("abc", "one two three", True),
("abc", "one two one", False),
("a", "dog", True),
("ab", "dog", False),
("aaa", "dog dog dog", True),
("abc", "dog cat", False),
],
)
def test_word_pattern(pattern, s, expected):
assert Solution().wordPattern(pattern, s) is expected
Comment on My Solution¶
Your solution is correct on the main idea, but a few things should be improved.
-
Good:
- You checked length first.
- You enforced uniqueness, so you did handle bijection.
-
Issues:
mapshadows Python's built-inmap.ch_word = map.get(ch, False)is unused.if map.get(ch, False)is a fragile pattern; useif ch in mapping.word in map.values()is \(O(n)\) each time, so the loop can become \(O(n^2)\).
A cleaner interview version uses two dictionaries and explicit membership checks.
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
map = {}
words = s.split()
if len(pattern) != len(words):
return False
for ch,word in zip(pattern, words):
ch_word = map.get(ch, False)
if map.get(ch, False):
if map[ch] != word:
return False
else:
if word in map.values():
return False
else:
map[ch] = word
return True
# Written after reading AI comments
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
ch_to_word = {}
word_to_ch = {}
words = s.split()
if len(pattern) != len(words):
return False
for ch,word in zip(pattern, words):
if ch in ch_to_word:
if ch_to_word[ch] != word:
return False
else:
if word in word_to_ch:
return False
else:
ch_to_word[ch] = word
word_to_ch[word] = ch
return True