原文链接: https://leetcode-cn.com/problems/find-and-replace-pattern
英文原文
Given a list of strings words
and a string pattern
, return a list of words[i]
that match pattern
. You may return the answer in any order.
A word matches the pattern if there exists a permutation of letters p
so that after replacing every letter x
in the pattern with p(x)
, we get the desired word.
Recall that a permutation of letters is a bijection from letters to letters: every letter maps to another letter, and no two letters map to the same letter.
Example 1:
Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb" Output: ["mee","aqq"] Explanation: "mee" matches the pattern because there is a permutation {a -> m, b -> e, ...}. "ccc" does not match the pattern because {a -> c, b -> c, ...} is not a permutation, since a and b map to the same letter.
Example 2:
Input: words = ["a","b","c"], pattern = "a" Output: ["a","b","c"]
Constraints:
1 <= pattern.length <= 20
1 <= words.length <= 50
words[i].length == pattern.length
pattern
andwords[i]
are lowercase English letters.
中文题目
你有一个单词列表 words
和一个模式 pattern
,你想知道 words
中的哪些单词与模式匹配。
如果存在字母的排列 p
,使得将模式中的每个字母 x
替换为 p(x)
之后,我们就得到了所需的单词,那么单词与模式是匹配的。
(回想一下,字母的排列是从字母到字母的双射:每个字母映射到另一个字母,没有两个字母映射到同一个字母。)
返回 words
中与给定模式匹配的单词列表。
你可以按任何顺序返回答案。
示例:
输入: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
通过代码
官方题解
方法一:双映射表
我们可以用两个映射表(map)存储字母到字母的映射关系,第一个映射表保证一个字母不会映射到两个字母,第二个映射表保证不会有两个字母映射到同一个字母。例如 word
为 a
,pattern
为 x
,那么第一个映射表存储 a -> x
,第二个映射表存储 x -> a
。
class Solution {
public List<String> findAndReplacePattern(String[] words, String pattern) {
List<String> ans = new ArrayList();
for (String word: words)
if (match(word, pattern))
ans.add(word);
return ans;
}
public boolean match(String word, String pattern) {
Map<Character, Character> m1 = new HashMap();
Map<Character, Character> m2 = new HashMap();
for (int i = 0; i < word.length(); ++i) {
char w = word.charAt(i);
char p = pattern.charAt(i);
if (!m1.containsKey(w)) m1.put(w, p);
if (!m2.containsKey(p)) m2.put(p, w);
if (m1.get(w) != p || m2.get(p) != w)
return false;
}
return true;
}
}
class Solution(object):
def findAndReplacePattern(self, words, pattern):
def match(word):
m1, m2 = {}, {}
for w, p in zip(word, pattern):
if w not in m1: m1[w] = p
if p not in m2: m2[p] = w
if (m1[w], m2[p]) != (p, w):
return False
return True
return filter(match, words)
复杂度分析
时间复杂度:$O(N * K)$,其中 $N$ 是数组
words
的长度,$K$ 是每个单词的长度。空间复杂度:$O(N * K)$。
方法二:单映射表
我们可以删去方法一中的第二个映射表,改成在添加完所有映射关系后,遍历第一个映射表并使用一个数组记录每个值出现的次数。如果某个值出现了超过一次,就说明有两个字母映射到同一个字母,否则映射就是合法的。
class Solution {
public List<String> findAndReplacePattern(String[] words, String pattern) {
List<String> ans = new ArrayList();
for (String word: words)
if (match(word, pattern))
ans.add(word);
return ans;
}
public boolean match(String word, String pattern) {
Map<Character, Character> M = new HashMap();
for (int i = 0; i < word.length(); ++i) {
char w = word.charAt(i);
char p = pattern.charAt(i);
if (!M.containsKey(w)) M.put(w, p);
if (M.get(w) != p) return false;
}
boolean[] seen = new boolean[26];
for (char p: M.values()) {
if (seen[p - 'a']) return false;
seen[p - 'a'] = true;
}
return true;
}
}
class Solution(object):
def findAndReplacePattern(self, words, pattern):
def match(word):
P = {}
for x, y in zip(pattern, word):
if P.setdefault(x, y) != y:
return False
return len(set(P.values())) == len(P.values())
return filter(match, words)
复杂度分析
时间复杂度:$O(N * K)$,其中 $N$ 是数组
words
的长度,$K$ 是每个单词的长度。空间复杂度:$O(N * K)$。
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
9097 | 12515 | 72.7% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|