Word Pattern I and II
XXX. Word Pattern and Word Pattern Matching
Problem Statement:
Word Pattern: Given a pattern and a string str
, find if str
follows the same pattern. Each character in the pattern maps to a word in str
uniquely.
Word Pattern Matching: Given a pattern and a string str
, determine if the pattern can be mapped to str
such that each character in the pattern maps to a substring in str
uniquely.
Algorithm:
Word Pattern:
- Split the string
str
into an array of words using space as a delimiter. - Check if the length of the pattern matches the number of words in
str
. If not, returnfalse
. - Use a hash map to store the mapping of pattern characters to words and a set to track used words.
- For each character in the pattern:
- If the character is already mapped, check if the word matches the mapped word. If not, return
false
. - If the character is not mapped but the word is already in the set, return
false
. - Otherwise, add the mapping and the word to the set.
- If the character is already mapped, check if the word matches the mapped word. If not, return
Word Pattern Matching:
- Use a backtracking approach to explore all possible mappings:
- If the pattern is exhausted and the string is also exhausted, return
true
. - If either the pattern or the string is exhausted, return
false
. - For each substring of the string:
- If the character is already mapped, check if the substring matches the mapped substring.
- If the character is not mapped and the substring is not already used, map the character to the substring and recurse for the remaining pattern and string.
Complexity:
Word Pattern:
Time Complexity: O(n), where n
is the length of the string.
Space Complexity: O(n) for the hash map and set.
Word Pattern Matching:
Time Complexity: O(n * m), where n
is the length of the pattern and m
is the length of the string.
Space Complexity: O(n + m) for the hash map and set.
Java Implementation:
public boolean wordPattern(String pattern, String str) {
String[] words = str.split(" ");
Map map = new HashMap<>();
Set set = new HashSet<>();
if (pattern.length() != words.length) return false;
for (int i = 0; i < words.length; i++) {
char c = pattern.charAt(i);
String word = words[i];
if (map.containsKey(c)) {
if (!map.get(c).equals(word)) return false; // Character already mapped
} else {
if (set.contains(word)) return false; // Word already used
map.put(c, word);
set.add(word);
}
}
return true;
}
public boolean wordPatternMatch(String pattern, String str) {
Map map = new HashMap<>();
Set set = new HashSet<>();
return backtrack(pattern, str, 0, 0, map, set);
}
public boolean backtrack(String pattern, String str, int index, int start, Map map, Set set) {
if (index == pattern.length() && start == str.length()) return true;
if (index == pattern.length() || start == str.length()) return false;
char c = pattern.charAt(index);
for (int i = start; i < str.length(); i++) {
String sub = str.substring(start, i + 1);
if (map.containsKey(c)) {
if (map.get(c).equals(sub))
if (backtrack(pattern, str, index + 1, i + 1, map, set)) return true;
} else if (!set.contains(sub)) {
map.put(c, sub);
set.add(sub);
if (backtrack(pattern, str, index + 1, i + 1, map, set)) return true;
map.remove(c);
set.remove(sub);
}
}
return false;
}
Python Implementation:
def wordPattern(pattern, s):
words = s.split()
char_to_word = {}
used_words = set()
if len(pattern) != len(words):
return False
for c, word in zip(pattern, words):
if c in char_to_word:
if char_to_word[c] != word:
return False
else:
if word in used_words:
return False
char_to_word[c] = word
used_words.add(word)
return True
def wordPatternMatch(pattern, s):
def backtrack(index, start):
if index == len(pattern) and start == len(s):
return True
if index == len(pattern) or start == len(s):
return False
char = pattern[index]
for i in range(start, len(s)):
sub = s[start:i + 1]
if char in char_to_word:
if char_to_word[char] == sub:
if backtrack(index + 1, i + 1):
return True
elif sub not in used_words:
char_to_word[char] = sub
used_words.add(sub)
if backtrack(index + 1, i + 1):
return True
del char_to_word[char]
used_words.remove(sub)
return False
char_to_word = {}
used_words = set()
return backtrack(0, 0)
C++ Implementation:
#include
#include
#include
using namespace std;
bool wordPattern(string pattern, string s) {
vector words;
string word;
stringstream ss(s);
while (ss >> word) words.push_back(word);
if (pattern.size() != words.size()) return false;
unordered_map charToWord;
unordered_set usedWords;
for (int i = 0; i < pattern.size(); ++i) {
char c = pattern[i];
if (charToWord.count(c)) {
if (charToWord[c] != words[i]) return false;
} else {
if (usedWords.count(words[i])) return false;
charToWord[c] = words[i];
usedWords.insert(words[i]);
}
}
return true;
}
bool wordPatternMatch(string pattern, string s) {
function backtrack = [&](int index, int start) {
if (index == pattern.size() && start == s.size()) return true;
if (index == pattern.size() || start == s.size()) return false;
char c = pattern[index];
for (int i = start; i < s.size(); ++i) {
string sub = s.substr(start, i - start + 1);
if (charToWord.count(c)) {
if (charToWord[c] == sub) {
if (backtrack(index + 1, i + 1)) return true;
}
} else if (!usedWords.count(sub)) {
charToWord[c] = sub;
usedWords.insert(sub);
if (backtrack(index + 1, i + 1)) return true;
charToWord.erase(c);
usedWords.erase(sub);
}
}
return false;
};
unordered_map charToWord;
unordered_set usedWords;
return backtrack(0, 0);
}