[LeetCode] 890. Find and Replace Pattern 查找和替换模式



You have a list of words and a pattern, and you want to know which words in words matches the pattern.html

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.git

(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.)github

Return a list of the words in words that match the given pattern. 数组

You may return the answer in any order.设计

Example 1:code

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.

Note:orm

  • 1 <= words.length <= 50
  • 1 <= pattern.length = words[i].length <= 20



这道题给了咱们一个字符串数组 words,还有一个 pattern 单词,问 words 数组中的单词是否知足 pattern 的模式,并给了一个例子。好比 pattern 是 abb 的话,表示后两个字母是相同的,好比 mee 和 aqq,那么一个很直接的想法就是创建每一个单词 word 和 pattern 中每一个字符之间的映射,好比 mee->abb 的话,就是 m->a, e->b,在创建映射以前要判断,若已经存在了该映射,且映射值不是当前 pattern 中的对应字符时,就是没法匹配的,好比 mm 和 ab,在第一次创建了 m->a 的映射,当遍历到第二个m的时候,发现m的映射已经存在,但不是b,就不能再创建 m->b 的映射,则表示没法匹配。分析到这里,你可能感受没啥问题,但其实咱们忽略一种状况,word 和 pattern 中的每一个字符必须是一一对应的,任何一个方向的多对一都是不行了,好比 mn 和 aa,刚开始创建了 m->a 的映射,遍历到n的时候,发现没有n的映射,此时也不能创建 n->a 的映射,由于 pattern 中的a已经被占用了,因此还须要一个 HashMap 来创建反方向的映射,只有两个 HashMap 中都不存在的,才能创建映射,只要有一个已经存在了,直接 break 掉。在 for 循环结束后,看是否已经到达了 word 的末尾,没有提早 break 掉的话,就将 word 加入结果 res 中便可,参见代码以下:htm



解法一:blog

class Solution {
public:
    vector<string> findAndReplacePattern(vector<string>& words, string pattern) {
        vector<string> res;
        for (string word : words) {
            unordered_map<char, char> w2p, p2w;
            int i = 0, n = word.size();
            for (; i < n; ++i) {
                if (w2p.count(word[i]) && w2p[word[i]] != pattern[i]) break;
                w2p[word[i]] = pattern[i];
                if (p2w.count(pattern[i]) && p2w[pattern[i]] != word[i]) break;
                p2w[pattern[i]] = word[i];
            }
            if (i == n) res.push_back(word);
        }
        return res;
    }
};



咱们也能够不用 HashMap,改用两个长度为 26 的数组,由于这道题貌似默认都是小写字母,惟一麻烦一点的就是要把字母减去 'a' 来转为对应的坐标,还有一点跟上面解法不一样的地方就是,字母是跟起坐标位置加1来创建映射(加1的缘由是默认值是0,而当 i=0 时为了区分默认值,就要加1),由于两个字母都跟一个特定的值相等,其实也等价于这两个字母之间创建的映射(a->c, b->c => a->b)。总体思路仍是没啥不一样的,参见代码以下:ci



解法二:

class Solution {
public:
    vector<string> findAndReplacePattern(vector<string>& words, string pattern) {
        vector<string> res;
        for (string word : words) {
            vector<int> w(26), p(26);
            int i = 0, n = word.size();
            for (; i < n; ++i) {
                if (w[word[i] - 'a'] != p[pattern[i] - 'a']) break;
                w[word[i] - 'a'] = p[pattern[i] - 'a'] = i + 1;
            }
            if (i == n) res.push_back(word);
        }
        return res;
    }
};



在论坛上又看到了一种解法,这种解法至关于把全部的单词都转为了一种特定的模式,具体来讲,就是用一个 HashMap,创建每一个字母跟其以前出现过的字母种类个数以前的映射,好比 mee->011,aqq->011,这样相同的模式映射的值是同样的,具体的作法是若当前字母没有出现过,则创建和当前 HashMap 中的映射个数之间的映射,是一种很巧妙的设计思路,只不过最后又给每一个数字加上了 'a',转为了字母的 pattern,即 mee->abb,aqq->abb,参见代码以下:



解法三:

class Solution {
public:
    vector<string> findAndReplacePattern(vector<string>& words, string pattern) {
        vector<string> res;
        for (string word : words) {
            if (helper(word) == helper(pattern)) res.push_back(word);
        }
        return res;
    }
    string helper(string word) {
        unordered_map<char, int> m;
        for (char c : word) {
            if (!m.count(c)) m[c] = m.size();
        }
        for (int i = 0; i < word.size(); ++i) word[i] = 'a' + m[word[i]];
        return word;
    }
};



Github 同步地址:

https://github.com/grandyang/leetcode/issues/890



相似题目:

Repeated Substring Pattern

132 Pattern

Word Pattern II

Word Pattern



参考资料:

https://leetcode.com/problems/find-and-replace-pattern/

https://leetcode.com/problems/find-and-replace-pattern/discuss/161266/JAVA-3ms-Clear-Code

https://leetcode.com/problems/find-and-replace-pattern/discuss/161288/C%2B%2BJavaPython-Normalise-Word



LeetCode All in One 题目讲解汇总(持续更新中...)

相关文章
相关标签/搜索