LeetCode890. 查找和替换模式
题目描述
本题目来自LeetCode上的『890. 查找和替换模式』
你有一个单词列表 words
和一个模式 pattern
,你想知道 words
中的哪些单词与模式匹配。
如果存在字母的排列 p
,使得将模式中的每个字母 x
替换为 p(x)
之后,我们就得到了所需的单词,那么单词与模式是匹配的。
(回想一下,字母的排列是从字母到字母的双射:每个字母映射到另一个字母,没有两个字母映射到同一个字母。)
返回 words
中与给定模式匹配的单词列表。
你可以按任何顺序返回答案。
示例1:
输入: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$ 的字符集为 $X$,$pattern$ 的字符集为 $Y$,题目要求我们定义一个双射 $f(X)\mapsto Y$。
使用一个哈希表来记录 $X$ 到 $Y$ 的映射,为了满足单射,需要一个数组来记录 $Y$ 中字符是否已经被映射,同时检查相同的的字符映射的字符是否相同。由于两个字符串等长,容易证明满足上述条件的单射是一个满射。
代码
class Solution {
public:
vector<string> findAndReplacePattern(vector<string>& words, string pattern) {
int mp[26], visited[26];
vector<string> ans;
for (const auto& word: words) {
fill(mp, mp + 26, -1);
fill(visited, visited + 26, 0);
int n = word.size();
int i = 0;
for (; i < n; ++i) {
int idx1 = word[i] - 'a', idx2 = pattern[i] - 'a';
if (mp[idx1] == -1 && !visited[idx2]) {
mp[idx1] = idx2;
visited[idx2] = 1;
} else if (mp[idx1] != idx2) {
break;
}
}
if (i == n) {
ans.emplace_back(word);
}
}
return ans;
}
};
复杂度分析
- 时间复杂度:$O(mn+mC)$,$m$ 是 $words$ 的长度,$n$ 是每个字符串的长度,$C$ 是字符的个数此处为 $26$。
- 空间复杂度:$O(C)$