Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 890. Find and Replace Pattern #890

Open
grandyang opened this issue May 30, 2019 · 0 comments
Open

[LeetCode] 890. Find and Replace Pattern #890

grandyang opened this issue May 30, 2019 · 0 comments

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019

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

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

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

You may return the answer in any order.

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.

Note:

  • 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 中即可,参见代码如下:
解法一:

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)。整体思路还是没啥不同的,参见代码如下:
解法二:

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 同步地址:

#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 题目讲解汇总(持续更新中...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant