# Question

Formatted question description: https://leetcode.ca/all/290.html

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.

Example 1:

Input: pattern = "abba", s = "dog cat cat dog"
Output: true


Example 2:

Input: pattern = "abba", s = "dog cat cat fish"
Output: false


Example 3:

Input: pattern = "aaaa", s = "dog cat cat dog"
Output: false


Constraints:

• 1 <= pattern.length <= 300
• pattern contains only lower-case English letters.
• 1 <= s.length <= 3000
• s contains only lowercase English letters and spaces ' '.
• s does not contain any leading or trailing spaces.
• All the words in s are separated by a single space.

# Algorithm

If the one-to-one mapping cannot be established, return false directly.

It also returns false when the mapping values of the two HashMaps are not the same.

# Code

• import java.util.HashMap;
import java.util.Map;

public class Word_Pattern {

public class Solution {
public boolean wordPattern(String pattern, String str) {
if (pattern == null || pattern.length() == 0 || str == null || str.length() == 0) {
return false;
}

String[] tokens = str.split(" ");

if (pattern.length() != tokens.length) {
return false;
}

Map<String, Character> inverseMap = new HashMap<>();
Map<Character, String> map = new HashMap<>();

for (int i = 0; i < pattern.length(); i++) {
char c = pattern.charAt(i);
String token = tokens[i];

// Check the one-one mapping
if (!map.containsKey(c) && !inverseMap.containsKey(token)) {
map.put(c, token);
inverseMap.put(token, c);
} else if (map.containsKey(c) && inverseMap.containsKey(token)) {
String tokenToCheck = map.get(c);
char charToCheck = inverseMap.get(token);

if (!tokenToCheck.equals(token) || c != charToCheck) {
return false;
}
} else { // @note: this is for different length of pattern and str
return false;
}
}

return true;
}
}
}

############

class Solution {
public boolean wordPattern(String pattern, String s) {
String[] ss = s.split(" ");
int n = pattern.length();
if (n != ss.length) {
return false;
}
Map<Character, String> c2str = new HashMap<>();
Map<String, Character> str2c = new HashMap<>();
for (int i = 0; i < n; ++i) {
char k = pattern.charAt(i);
String v = ss[i];
if (c2str.containsKey(k) && !Objects.equals(c2str.get(k), v)) {
return false;
}
if (str2c.containsKey(v) && !Objects.equals(str2c.get(v), k)) {
return false;
}
c2str.put(k, v);
str2c.put(v, k);
}
return true;
}
}

• // OJ: https://leetcode.com/problems/word-pattern/
// Time: O(M + N)
// Space: O(M + N)
class Solution {
public:
bool wordPattern(string pattern, string str) {
unordered_map<char, string> m;
unordered_map<string, char> r;
istringstream ss(str);
string word;
for (char c : pattern) {
if (!(ss >> word)) return false;
if ((m.count(c) && m[c] != word)
|| r.count(word) && r[word] != c) return false;
m[c] = word;
r[word] = c;
}
return ss.eof();
}
};

• '''
>>> p = "abba"
>>> s = "dog cat cat dog".split()
>>> s
['dog', 'cat', 'cat', 'dog']
>>> zip(p,s)
[('a', 'dog'), ('b', 'cat'), ('b', 'cat'), ('a', 'dog')]
>>> set(zip(p,s))
set([('b', 'cat'), ('a', 'dog')])
>>>
>>>
>>> s = "dog dog dog dog".split() # then false for: len(set(pattern)) == len(set(str))
>>> zip(p,s)
[('a', 'dog'), ('b', 'dog'), ('b', 'dog'), ('a', 'dog')]
>>> set(zip(p,s))
set([('a', 'dog'), ('b', 'dog')])
'''

class Solution(object):
def wordPattern(self, pattern, s):
"""
:type pattern: str
:type s: str
:rtype: bool
"""
s = s.split()
a = zip(pattern, s)
return len(pattern) == len(s) and len(set(a)) == len(set(pattern)) == len(set(s))

############

class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
s = s.split(' ')
n = len(pattern)
if n != len(s):
return False
c2str, str2c = defaultdict(), defaultdict()
for i in range(n):
k, v = pattern[i], s[i]
if k in c2str and c2str[k] != v:
return False
if v in str2c and str2c[v] != k:
return False
c2str[k], str2c[v] = v, k
return True


• func wordPattern(pattern string, s string) bool {
ss := strings.Split(s, " ")
n := len(pattern)
if n != len(ss) {
return false
}
c2str := make(map[byte]string)
str2c := make(map[string]byte)
for i := 0; i < n; i++ {
k, v := pattern[i], ss[i]
if c2str[k] != "" && c2str[k] != v {
return false
}
if str2c[v] > 0 && str2c[v] != k {
return false
}
c2str[k], str2c[v] = v, k
}
return true
}

• function wordPattern(pattern: string, s: string): boolean {
let n = pattern.length;
let values = s.split(' ');
if (n != values.length) return false;
let table = new Array(128);
for (let i = 0; i < n; i++) {
let k = pattern.charCodeAt(i),
v = values[i];
if (!table[k]) {
if (table.includes(v)) return false;
table[k] = v;
} else {
if (table[k] != v) return false;
}
}
return true;
}


• use std::collections::HashMap;

impl Solution {
pub fn word_pattern(pattern: String, s: String) -> bool {
let cs1: Vec<char> = pattern.chars().collect();
let cs2: Vec<&str> = s.split_whitespace().collect();
let n = cs1.len();
if n != cs2.len() {
return false;
}
let mut map1 = HashMap::new();
let mut map2 = HashMap::new();
for i in 0..n {
let c = cs1[i];
let s = cs2[i];
if !map1.contains_key(&c) {
map1.insert(c, i);
}
if !map2.contains_key(&s) {
map2.insert(s, i);
}
if map1.get(&c) != map2.get(&s) {
return false
}
}
true
}
}


• public class Solution {
public bool WordPattern(string pattern, string s) {
var ws = s.Split(' ');
if (pattern.Length != ws.Length) {
return false;
}
var d1 = new Dictionary<char, string>();
var d2 = new Dictionary<string, char>();
for (int i = 0; i < ws.Length; ++i) {
var a = pattern[i];
var b = ws[i];
if (d1.ContainsKey(a) && d1[a] != b) {
return false;
}
if (d2.ContainsKey(b) && d2[b] != a) {
return false;
}
d1[a] = b;
d2[b] = a;
}
return true;
}
}