Description
Given a pattern
and a string s
, find if s
follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern
and a non-empty word in s
. Specifically:
- Each letter in
pattern
maps to exactly one unique word ins
. - Each unique word in
s
maps to exactly one letter inpattern
. - No two letters map to the same word, and no two words map to the same letter.
Examples:
Example 1:
Input: pattern = "abba", s = "dog cat cat dog"
Output: true
Explanation:
The bijection can be established as:
'a' maps to "dog".
'b' maps to "cat".
Example 2:
Input: pattern = "abba", s = "dog cat cat fish"
Output: false
Example 3:
Input: pattern = "aaaa", s = "dog cat cat dog"
Output: false
Solution in Python
Python
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
# Split the string 's' into a list of words
words = s.split()
# If the lengths of pattern and words do not match, it cannot follow the pattern
if len(pattern) != len(words):
return False
# Dictionary to map letters from pattern to words
pattern_to_word = {}
# Dictionary to map words to letters from pattern (for checking bijection)
word_to_pattern = {}
# Iterate over both the pattern and corresponding words simultaneously
for p, word in zip(pattern, words):
# Check if there is already a mapping from pattern to word
if p in pattern_to_word:
# If the current mapping does not match the word, return False
if pattern_to_word[p] != word:
return False
else:
# Check if the word is already mapped to a different letter
if word in word_to_pattern:
return False
# Create new mappings in both dictionaries
pattern_to_word[p] = word
word_to_pattern[word] = p
# If all checks passed, return True
return True
Detailed Explanation:
- Splitting the String
s
:- We split the input string
s
into a list of words usingsplit()
, which breaks the string by spaces.
- We split the input string
- Length Mismatch Check:
- If the number of characters in
pattern
doesn’t match the number of words ins
, it’s impossible to establish a bijection. In that case, we returnFalse
.
- If the number of characters in
- Two Dictionaries:
- We create two dictionaries:
pattern_to_word
: Maps each character inpattern
to a corresponding word ins
.word_to_pattern
: Maps each word ins
back to the corresponding character inpattern
. This helps ensure the bijection (one-to-one mapping) is maintained.
- We create two dictionaries:
- Iterating through the Pattern and Words:
- We use the
zip
function to iterate through bothpattern
andwords
simultaneously. - For each pair
(p, word)
:- If
p
(the character frompattern
) is already mapped to a word, we check if it matches the current word. If not, returnFalse
. - If the word is already mapped to a different letter (in
word_to_pattern
), returnFalse
. - If no mapping exists, we create new mappings in both dictionaries.
- If
- We use the
- Return True:
- If the loop completes without any inconsistencies, return
True
, indicating that the strings
follows the same pattern.
- If the loop completes without any inconsistencies, return
This approach ensures that we maintain a bijection between characters in pattern
and words in s
. The time complexity is O(n), where n
is the length of pattern
, since we loop through both the pattern
and s
once.
Solution in C++
C++
#include <unordered_map>
#include <sstream>
#include <vector>
#include <string>
class Solution {
public:
bool wordPattern(std::string pattern, std::string s) {
// Split the string s into words
std::istringstream stream(s);
std::vector<std::string> words;
std::string word;
// Read words from the string stream into the words vector
while (stream >> word) {
words.push_back(word);
}
// If the length of the pattern does not match the number of words, return false
if (pattern.length() != words.size()) {
return false;
}
// Maps to establish the one-to-one relationship
std::unordered_map<char, std::string> patternToWord;
std::unordered_map<std::string, char> wordToPattern;
// Iterate over the pattern and the words simultaneously
for (int i = 0; i < pattern.length(); ++i) {
char p = pattern[i];
const std::string& w = words[i];
// Check if there's already a mapping for the character in the pattern
if (patternToWord.count(p)) {
// If the current mapping does not match the expected word, return false
if (patternToWord[p] != w) {
return false;
}
} else {
// If the character is not mapped yet, check if the word is already mapped
if (wordToPattern.count(w)) {
return false; // The word is already associated with a different character
}
// Create new mappings in both dictionaries
patternToWord[p] = w;
wordToPattern[w] = p;
}
}
// If all checks are passed, the pattern matches the string
return true;
}
};
Solution in Javascript
JavaScript
var wordPattern = function(pattern, s) {
// Split the string 's' into an array of words
const words = s.split(' ');
// If the length of pattern does not match the number of words, return false
if (pattern.length !== words.length) {
return false;
}
// Create two maps to establish the one-to-one relationship
const patternToWord = new Map();
const wordToPattern = new Map();
// Iterate through the pattern and corresponding words simultaneously
for (let i = 0; i < pattern.length; i++) {
const p = pattern[i]; // Current character in the pattern
const word = words[i]; // Corresponding word from the array
// Check if there is already a mapping for the character in the pattern
if (patternToWord.has(p)) {
// If the current mapping does not match the expected word, return false
if (patternToWord.get(p) !== word) {
return false;
}
} else {
// If the character is not mapped yet, check if the word is already mapped
if (wordToPattern.has(word)) {
return false; // The word is already associated with a different character
}
// Create new mappings in both maps
patternToWord.set(p, word);
wordToPattern.set(word, p);
}
}
// If all checks passed, the pattern matches the string
return true;
};
Solution in Java
Java
import java.util.HashMap;
import java.util.Map;
class Solution {
public boolean wordPattern(String pattern, String s) {
// Split the string 's' into an array of words
String[] words = s.split(" ");
// If the length of pattern does not match the number of words, return false
if (pattern.length() != words.length) {
return false;
}
// Create two maps to establish the one-to-one relationship
Map<Character, String> patternToWord = new HashMap<>();
Map<String, Character> wordToPattern = new HashMap<>();
// Iterate through the pattern and corresponding words simultaneously
for (int i = 0; i < pattern.length(); i++) {
char p = pattern.charAt(i); // Current character in the pattern
String word = words[i]; // Corresponding word from the array
// Check if there is already a mapping for the character in the pattern
if (patternToWord.containsKey(p)) {
// If the current mapping does not match the expected word, return false
if (!patternToWord.get(p).equals(word)) {
return false;
}
} else {
// If the character is not mapped yet, check if the word is already mapped
if (wordToPattern.containsKey(word)) {
return false; // The word is already associated with a different character
}
// Create new mappings in both maps
patternToWord.put(p, word);
wordToPattern.put(word, p);
}
}
// If all checks passed, the pattern matches the string
return true;
}
}