**输入:** words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
**输出:** ["mee","aqq"]
**解释:** "mee" 与模式匹配,因为存在排列 {a -> m, b -> e, ...}。
"ccc" 与模式不匹配,因为 {a -> c, b -> c, ...} 不是排列。
因为 a 和 b 映射到同一个字母。
提示:
1 <= words.length <= 50
1 <= pattern.length = words[i].length <= 20
方法一:构造双射
我们可以逐个判断 words 中的每个单词 word 是否与 pattern 匹配。
根据题意,我们需要构造从字母到字母的双射,即 word 的每个字母需要映射到 pattern 的对应字母,并且 pattern 的每个字母也需要映射到 word 的对应字母。
我们可以编写一个函数 match}(\textit{word},\textit{pattern}),仅当 word 中相同字母映射到 pattern 中的相同字母时返回 true。我们可以在遍历这两个字符串的同时,用一个哈希表记录 word 的每个字母 x 需要映射到 pattern 的哪个字母上,如果 x 已有映射,则需要检查对应字母是否相同。
如果 match}(\textit{word},\textit{pattern}) 和 match}(\textit{pattern},\textit{word}) 均为 true,则表示 word 与 pattern 匹配。
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11
classSolution: deffindAndReplacePattern(self, words: List[str], pattern: str) -> List[str]: defmatch(word: str, pattern: str) -> bool: mp = {} for x, y inzip(word, pattern): if x notin mp: mp[x] = y elif mp[x] != y: # word 中的同一字母必须映射到 pattern 中的同一字母上 returnFalse returnTrue return [word for word in words ifmatch(word, pattern) andmatch(pattern, word)]
funcmatch(word, pattern string)bool { mp := map[rune]byte{} for i, x := range word { y := pattern[i] if mp[x] == 0 { mp[x] = y } elseif mp[x] != y { // word 中的同一字母必须映射到 pattern 中的同一字母上 returnfalse } } returntrue }
funcfindAndReplacePattern(words []string, pattern string) (ans []string) { for _, word := range words { if match(word, pattern) && match(pattern, word) { ans = append(ans, word) } } return }
var findAndReplacePattern = function(words, pattern) { const ans = []; for (const word of words) { if (match(word, pattern) && match(pattern, word)) { ans.push(word); } } return ans; };
constmatch = (word, pattern) => { const map = newMap(); for (let i = 0; i < word.length; ++i) { const x = word[i], y = pattern[i]; if (!map.has(x)) { map.set(x, y); } elseif (map.get(x) !== y) { // word 中的同一字母必须映射到 pattern 中的同一字母上 returnfalse; } } returntrue; }
复杂度分析
时间复杂度:O(nm),其中 n 是数组 words 的长度,m 是 pattern 的长度。对于每个 word 需要 O(m) 的时间检查其是否与 pattern 匹配。