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

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

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 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM