Last Updated: March 29, 2026
We're given a pattern like "abba" and a sentence like "dog cat cat dog". The question is whether there's a one-to-one correspondence between letters in the pattern and words in the sentence. 'a' always maps to the same word, 'b' always maps to the same word, and no two different letters map to the same word.
The tricky part is that the mapping must be bijective, meaning it goes both ways. It's not enough for each letter to consistently map to the same word. We also need each word to consistently map to the same letter. For example, pattern "ab" and string "dog dog" should return false because both 'a' and 'b' would map to "dog", violating the bijection.
So the key observation is: we need to track two mappings simultaneously. One from characters to words, and another from words to characters. If either mapping is violated, the answer is false.
1 <= pattern.length <= 300 -- The pattern is very small. Even O(n^2) would be fine, but O(n) is natural here.1 <= s.length <= 3000 -- The string is also small. No need to worry about performance at all.pattern contains only lowercase English letters -- At most 26 distinct characters. A fixed-size array could work for the char-to-word mapping.The most natural approach: walk through the pattern and words in parallel, maintaining a mapping in both directions.
When we see a pattern character and a word together for the first time, we create a bidirectional mapping. If we see them again, we verify the existing mapping still holds. If a character was previously mapped to a different word, or a word was previously mapped to a different character, the bijection is broken.
Why two maps? Because a single map only enforces one direction. If we only track char-to-word, pattern "ab" with "dog dog" would incorrectly pass: 'a' -> "dog" is fine, and 'b' -> "dog" doesn't conflict with any existing mapping in a char-to-word map. But it violates the bijection because "dog" is now mapped to two different characters. The word-to-char map catches this.
A bijection means every element in one set maps to exactly one element in the other set, and vice versa. By maintaining two hash maps, we're explicitly enforcing both directions of this bijection. The charToWord map ensures each character consistently maps to the same word. The wordToChar map ensures each word consistently maps to the same character. Together, they guarantee the one-to-one correspondence the problem requires.
s into an array of words.pattern, return false.charToWord (character -> string) and wordToChar (string -> character).i, get the current pattern character and the current word.charToWord, check that it maps to the current word. If not, return false.wordToChar, check that it maps to the current character. If not, return false.true.This approach works well and directly models the bijection. But what if instead of tracking explicit mappings, we just encoded the structure of each sequence and compared the encodings directly?
Two sequences follow the same pattern if and only if they have the same "first occurrence" structure. Consider pattern "abba": the first occurrence indices are [0, 1, 1, 0], because 'a' first appears at index 0, 'b' first appears at index 1, 'b' was already seen at index 1, and 'a' was already seen at index 0. If the words "dog cat cat dog" produce the same structure [0, 1, 1, 0], the pattern matches.
This approach avoids the explicit bijection check entirely. Instead of asking "does the mapping hold in both directions?", we ask "do both sequences have the same structural fingerprint?"
Two sequences follow the same pattern when they have the same structure of repetitions. The first-occurrence index captures this structure perfectly. If 'a' first appears at index 0 and reappears at index 3, then the corresponding word must also first appear at index 0 and reappear at index 3. By comparing first-occurrence indices at each position, we're comparing the structural fingerprints of both sequences. This implicitly enforces the bijection without needing two separate maps.
s into words. If the count doesn't match pattern length, return false.false.true.