Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Split the sentence into words and require a bijection between pattern characters and words: each pattern char maps to exactly one word AND each word maps back to exactly one pattern char. Like Isomorphic Strings, one map is not enough — track both directions. Guard the length first: number of words must equal the pattern length. O(n) time, O(n) space.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you recognize this as the same bijection problem as Isomorphic Strings, just with words instead of characters — and whether you remember to verify the mapping in both directions.
Where candidates slip
Only mapping char→word (so 'abba' with 'dog dog dog dog' wrongly passes), or comparing lengths of the raw strings instead of pattern length vs word count.
How to stand out
Say 'this is Isomorphic Strings with words as tokens' immediately, handle the split-and-count guard explicitly, and mention the single-map-with-index-encoding alternative.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewSplit s into wordslen(pattern) == #words?NoYesExplore the full treeCollapse the tree
pattern = "abba", s = "dog dog dog dog"How to read it:Forward map looks fine until the reverse map rejects b→dog because dog already belongs to a.
- Frame 1
i=0, a/doga unseen, dog unclaimed → a→dog, dog→a
a→ dog - Frame 2
i=1, b/dogb unseen forward, BUT dog already claimed by a in reverse → false
a→ dogLooked upb— not in map.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2 · Optimal
Two Hash Maps — char↔word Bijection (Optimal)
1Hint 1Explore hintHide hint
What does 'bijection' demand beyond 'every pattern char picks a word'? It also demands that no two pattern chars pick the SAME word. That reverse condition needs its own map.
2Hint 2Explore hintHide hint
Split s into words first. If the word count differs from the pattern length, return false before doing anything else.
3Hint 3Explore hintHide hint
Keep c2w (char→word) and w2c (word→char). For each pair, fail if either direction already disagrees; otherwise record both.
A · Core idea
After splitting the sentence into a list of words, the problem is identical in shape to Isomorphic Strings: we need a bijection between two sequences of equal length — here the pattern's characters and the sentence's words. We walk both sequences in lockstep and enforce consistency in both directions.
Why this is the same problem as Isomorphic Strings. In Isomorphic Strings the second alphabet was individual characters of t; here it is whole words. Nothing else changes. The bijection requirement — each pattern char maps to exactly one word and each word maps back to exactly one char — is structurally the same constraint. Recognizing this lets you reuse a battle-tested template instead of inventing logic under pressure. Saying that out loud signals pattern fluency to the interviewer.
Why both maps are mandatory. Consider pattern = "abba", s = "dog dog dog dog". A char→word map records a→dog, then at the b/dog pair b is unseen, so a forward-only check happily adds b→dog. But now two pattern chars (a and b) both point at dog, violating one-to-one. The reverse map w2c already contains dog→a, so when b tries to claim dog we detect that dog is taken and return false. The forward map catches char→word conflicts ("aaaa" vs "dog cat cat dog"); the reverse map catches word→char conflicts. You need both because a bijection has two halves.
Why the length guard comes first. Splitting "dog cat cat" yields three words; matching it against the four-character pattern "abba" is impossible. If you skip the guard and rely on zip, Python silently stops at the shorter sequence and might return true for a pattern that is genuinely longer. Comparing len(pattern) to the number of words after splitting closes that hole. Note: compare against the word count, never against len(s) — the raw string length is unrelated to the number of tokens.
Why check before write. As in every bijection scan, we verify both directions before inserting. If we inserted first, the new entry would trivially agree with itself and a conflict on that very step would be masked.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
pattern = "abba", s = "dog cat cat fish"Hash-map state
i=0, a/dog
aContinue scanning
new → a→dog
falseC · Code with teaching comments
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
The unit of mapping is the token, not the letter. The single conceptual leap from Isomorphic Strings is 'split the sentence, then treat each word as one symbol'. Once tokenized, the bijection machinery is identical — which is exactly why interviewers pair these two problems: they test whether you see past surface differences to the shared structure.
ComplexityO(n) time, O(n) space — Splitting is O(n) over the sentence. The single pass over k pairs does O(L) work per comparison where L is word length, totaling O(n). Maps hold up to k distinct words → O(n) space (words can be long, so space scales with input, unlike the fixed-alphabet char case).
E · Edge cases and pitfalls7pattern = "a", s = "dog" — Single pair, both new, record a→dog → true.Explore edge casesHide edge cases
Edge cases handled
pattern = "a", s = "dog"Single pair, both new, record a→dog → true.pattern = "ab", s = "dog dog"a→dog, then b/dog: dog claimed by a in w2c → false.pattern = "abc", s = "b c a"Three distinct chars, three distinct words, all 1-to-1 → true (words happen to look like letters, irrelevant).
Pitfalls
- Comparing pattern.length() to s.length() instead of words.length — those are unrelated.
- Using == on Strings in Java instead of .equals — reference vs value comparison.
- Only keeping a char→word map — passes 'abba' / 'dog dog dog dog' incorrectly.
- Assuming clean spacing without confirming; irregular spaces produce empty tokens.
Approach 2 of 2
Single Map of Index Signatures
1Hint 1Explore hintHide hint
Two sequences follow the same pattern iff their first-occurrence index signatures are identical. 'abba' → [0,1,1,0]; 'dog cat cat dog' → [0,1,1,0]. Equal → match.
2Hint 2Explore hintHide hint
Use one dictionary that records, for each distinct symbol, the index where it first appeared. Build the signature for the pattern and for the words and compare element by element.
3Hint 3Explore hintHide hint
putIfAbsent each symbol's first index; if at step i the pattern's recorded first index differs from the words' recorded first index, return false.
A · Core idea
Rather than two maps for two directions, this approach encodes each sequence as the list of first-occurrence indices of its symbols, then checks the two encodings are identical. It mirrors the index-encoding trick from Isomorphic Strings.
Why it works. Two sequences 'follow the same pattern' precisely when one can be relabeled into the other while preserving repetition structure. The first-occurrence index of each symbol is a label-independent fingerprint of that structure: for "abba", a first appears at 0, b at 1, so the signature is [0, 1, 1, 0]. For the words dog cat cat dog, dog first appears at 0, cat at 1, giving the same [0, 1, 1, 0]. Equal signatures ⇔ bijection exists. Because we compare the same index contributed by both sides at each position, a mismatch in either direction surfaces as a divergent signature — no separate reverse map needed.
Why use first-occurrence and not last-occurrence. Either works, but first-occurrence is the most natural canonical form: the i-th element of the signature answers "where did this symbol debut?" Two symbols that debut at the same step in both sequences must be 'the same role' in the pattern. If pattern's symbol debuted at step 3 but the corresponding word debuted at step 1, the word was already used for a different pattern char — a conflict.
Why it's worth mentioning but not the default. It's elegant and uses a single conceptual mechanism for both directions, which can impress. The downside is it's slightly more error-prone (you must use putIfAbsent / setdefault so only the first index is stored, and you still need the length guard). For most interviews the explicit two-map version reads more clearly, but offering this shows depth.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
pattern = "abba", s = "dog cat cat dog"i=0
first(a)=0, first(dog)=0 → equal
fp={a:0}, fw={dog:0}trueC · Code with teaching comments
Reference implementation previewpublic boolean wordPattern(String pattern, String s) { String[] words = s.split(" "); if (pattern.length() != words.length) return false; Map<Character, Integer> fp = new HashMap<>(); Map<String, Integer> fw = new HashMap<>();Explore the full codeHide the full code
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Pattern-following is invariance of repetition structure under relabeling. Encoding each sequence by 'first index of each symbol' collapses both the forward and reverse consistency into one signature comparison — the same canonical-form idea that powers Group Anagrams.
ComplexityO(n) time, O(n) space — One pass building both signatures with O(1) average map ops → O(n). Two maps holding up to k symbols → O(n) space.
E · Edge cases and pitfalls5pattern = "abba", s = "dog dog dog dog" — At i=1 first(b)=1 but first(dog)=0 → 1 != 0 → false.Explore edge casesHide edge cases
Edge cases handled
pattern = "abba", s = "dog dog dog dog"At i=1 first(b)=1 but first(dog)=0 → 1 != 0 → false.pattern = "aaaa", s = "dog cat cat dog"At i=1 first(a)=0 but first(cat)=1 → 0 != 1 → false.
Pitfalls
- Using put instead of putIfAbsent / setdefault — overwrites and stores last index, breaking the signature.
- Skipping the length guard — zip truncates in Python.
- Mixing int and Integer comparison carelessly in Java — unbox before ==.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic boolean wordPattern(String pattern, String s) { String[] words = s.split(" "); if (pattern.length() != words.length) return false; Map<Character, String> c2w = new HashMap<>(); Map<String, Character> w2c = new HashMap<>();Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Single map, missing reverse direction
Without word→char, two pattern chars can claim the same word. On 'abba' / 'dog dog dog dog', b→dog is added even though dog already belongs to a.
Explore the code comparisonHide the code comparison
Single map, missing reverse direction
Without word→char, two pattern chars can claim the same word. On 'abba' / 'dog dog dog dog', b→dog is added even though dog already belongs to a.
Don't write this
Map<Character,String> c2w = new HashMap<>();
for (int i = 0; i < words.length; i++) {
char c = pattern.charAt(i);
if (c2w.containsKey(c) && !c2w.get(c).equals(words[i])) return false;
c2w.put(c, words[i]);
}
return true;Write this instead
Map<Character,String> c2w = new HashMap<>();
Map<String,Character> w2c = new HashMap<>();
for (int i = 0; i < words.length; i++) {
char c = pattern.charAt(i);
String w = words[i];
if (c2w.containsKey(c) && !c2w.get(c).equals(w)) return false;
if (w2c.containsKey(w) && w2c.get(w) != c) return false;
c2w.put(c, w);
w2c.put(w, c);
}
return true;2Comparing the wrong lengths
pattern.length() counts characters; s.length() counts characters of the whole sentence including spaces. You must compare pattern length to the number of WORDS.
Explore the code comparisonHide the code comparison
Comparing the wrong lengths
pattern.length() counts characters; s.length() counts characters of the whole sentence including spaces. You must compare pattern length to the number of WORDS.
Don't write this
if len(pattern) != len(s):
return FalseWrite this instead
words = s.split(' ')
if len(pattern) != len(words):
return False3String identity vs equality in Java
c2w.get(c) == w compares references. Two equal-content Strings can be different objects, so this can wrongly return false. Use .equals.
Explore the code comparisonHide the code comparison
String identity vs equality in Java
c2w.get(c) == w compares references. Two equal-content Strings can be different objects, so this can wrongly return false. Use .equals.
Don't write this
if (c2w.containsKey(c) && c2w.get(c) != w) return false;Write this instead
if (c2w.containsKey(c) && !c2w.get(c).equals(w)) return false;Revise
Carry the pattern into the interview
Pattern to remember
Bijection between chars and words (two maps)
Code pattern to memorize
words = s.split(' ')
if len(pattern) != len(words): return False
for c, w in zip(pattern, words):
if c in c2w and c2w[c] != w: return False
if w in w2c and w2c[w] != c: return False
c2w[c] = w; w2c[w] = c
return TrueRules to remember
- 1Split on spaces FIRST and compare counts —
pattern="abba"vs words of length 3 is an instantfalse. - 2Check both directions: char→word and word→char.
pattern="abba", s="dog dog dog dog"must fail because b would map to dog which is already a's word. - 3A word may be multiple characters — the unit is the whole word, not a letter. Don't iterate the sentence char by char.
- 4Use
.split(' ')semantics carefully; leading/trailing/multiple spaces can create empty tokens — clarify input cleanliness. - 5Check before writing so a fresh entry can't agree with itself and hide a conflict.
Use this pattern when
- Mapping a short symbolic pattern onto a sequence of tokens / words
- Any 'does this template consistently describe this sequence?' question
- Tokens are multi-character but must translate one-to-one
- You recognize it as Isomorphic Strings lifted from chars to words
Choose another pattern when
- Only one direction matters → single map (rare; usually it's a true bijection)
- Order is irrelevant → frequency comparison instead
- Pattern can repeat words freely (many-to-one) → drop the reverse map
- You must output the mapping, not a boolean → store and return the dict
Interview takeaway
Word Pattern is Isomorphic Strings with words as the second alphabet. The exact same two-map bijection check applies — split into tokens, verify both directions. The classic trap is forgetting the reverse map or forgetting the length guard after splitting.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternBijection via two hash maps, tokenized to words. Recognise it as Isomorphic Strings whenever a short symbolic pattern must consistently and reversibly describe a sequence of tokens. The reverse map and the post-split length guard are the two things candidates forget.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Isomorphic StringsThe same bijection but between characters of two strings — Word Pattern is this lifted to words.
- Word Pattern IIComing soonNo spaces in s — you must backtrack over possible word boundaries while maintaining the bijection.
- Find and Replace PatternComing soonFilter a word list by whether each word is isomorphic to the pattern — reuse the bijection check per word.
- Group AnagramsCanonical-form grouping — same 'normalize then compare' idea as the index-signature approach.