加载中...
890-查找和替换模式(Find and Replace Pattern)
发表于:2021-12-03 | 分类: 中等
字数统计: 1.2k | 阅读时长: 6分钟 | 阅读量:

原文链接: 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 and words[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)存储字母到字母的映射关系,第一个映射表保证一个字母不会映射到两个字母,第二个映射表保证不会有两个字母映射到同一个字母。例如 wordapatternx,那么第一个映射表存储 a -> x,第二个映射表存储 x -> a

[sol1]
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; } }
[sol1]
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)$。

方法二:单映射表

我们可以删去方法一中的第二个映射表,改成在添加完所有映射关系后,遍历第一个映射表并使用一个数组记录每个值出现的次数。如果某个值出现了超过一次,就说明有两个字母映射到同一个字母,否则映射就是合法的。

[sol2]
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; } }
[sol2]
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%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
889-根据前序和后序遍历构造二叉树(Construct Binary Tree from Preorder and Postorder Traversal)
下一篇:
891-子序列宽度之和(Sum of Subsequence Widths)
本文目录
本文目录