291. Word Pattern II


Given a pattern and a string str, find if str follows the same pattern.

Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty substring in str.

Example 1:

Input: pattern = “abab”, str = “redblueredblue”
Output: true
Example 2:

Input: pattern = pattern = “aaaa”, str = “asdasdasdasd”
Output: true
Example 3:

Input: pattern = “aabb”, str = “xyzabcxzyabc”
Output: false
Notes:
You may assume both pattern and str contains only lowercase letters.

方法1: backtracking

思路:

和前一题相比,这道题str并没有被空格分开,需要一次次的尝试截断单词,并建立映射关系,每当有违反映射的情况出现,一层层的退回尝试新的截断方式。这就确定了backtracking的形式。在递归函数中传递一个patter和string的起始位置,终止条件是两个index同时遍历到尽头,标志着所有的映射都成立,可以返回true。但如果有一个已经遍历完了另一个却没有,那么可以肯定的返回false。否则冲pattern中先提取新的char c,然后尝试从s开始截断各种长度的string,判断有没有违反映射。第一种没有违反映射的条件是,之前已经建立过hash[c] = word,这里不用新建,直接向下递归。而第二种条件是,没有建立过这个映射,并且seen也没有见过这个word,i.e. 没有被映射到别的字母上过,那么就开始一次backtracking,向下递归。注意把两种成立条件一起处理是不对的,非本层建立的映射不能够在本层删除。另外这个递归的判断条件很容易遗漏情况,下面两种解法是对的。

易错点

  1. 终止条件。
  2. 判断双向映射都没有被违反。
  3. 没有违反的话,也要根据映射是否是第一次建立来决定要不要backtraking。
  4. 判断条件容易遗漏。

Complexity

Time complexity: O(2^n)
Space complexity: O(n)

class Solution1 {
public:
    bool wordPatternMatch(string pattern, string str) {
        unordered_map<char, string> hash;
        set<string> seen;
        return wordHelper(pattern, 0, str, 0, hash, seen);
    }
    
    bool wordHelper(string pattern, int p, string str, int s, unordered_map<char, string> & hash, set<string> & seen) {
        if (p == pattern.size() && s == str.size()) return true;
        if (p == pattern.size() || s == str.size()) return false;
        
        char c = pattern[p];
        for (int i = s; i < str.size(); i++) {
            string word = str.substr(s, i - s + 1);
            if (hash.count(c) && hash[c] == word) {
                if (wordHelper(pattern, p + 1, str, i + 1, hash, seen)) return true;
            }
            else if (!hash.count(c)) {
                if (seen.count(word)) continue;
                hash[c] = word;
                seen.insert(word);
                if (wordHelper(pattern, p + 1, str, i + 1, hash, seen)) return true;
                hash.erase(c);
                seen.erase(word);
            }
        }
        return false;
    }
};
class Solution {
public:
    bool wordPatternMatch(string pattern, string str) {
        unordered_map<char, string> hash;
        set<string> seen;
        return wordHelper(pattern, 0, str, 0, hash, seen);
    }
    
    bool wordHelper(string pattern, int p, string str, int s, unordered_map<char, string> & hash, set<string> & seen) {
        if (p == pattern.size() && s == str.size()) return true;
        if (p == pattern.size() || s == str.size()) return false;
        
        char c = pattern[p];
        for (int i = s; i < str.size(); i++) {
            string word = str.substr(s, i - s + 1);
            if (hash.count(c) && hash[c] == word) {
                if (wordHelper(pattern, p + 1, str, i + 1, hash, seen)) return true;
            }
            else if (!hash.count(c) && seen.count(word)) continue;
            else {
                if (hash.count(c)) continue;
                hash[c] = word;
                seen.insert(word);
                if (wordHelper(pattern, p + 1, str, i + 1, hash, seen)) return true;
                hash.erase(c);
                seen.erase(word);
            }
        }
        return false;
    }
};

另外有一种不用seen来检查逆向映射被违反的情况,每次遍历hash来找有word有没有被映射到别的字母上,居然比上面还要快。

class Solution {
public:
    bool wordPatternMatch(string pattern, string str) {
        unordered_map<char, string> m;
        return helper(pattern, 0, str, 0, m);
    }
    bool helper(string pattern, int p, string str, int r, unordered_map<char, string> &m) {
        if (p == pattern.size() && r == str.size()) return true;
        if (p == pattern.size() || r == str.size()) return false;
        char c = pattern[p];
        for (int i = r; i < str.size(); ++i) {
            string t = str.substr(r, i - r + 1);
            if (m.count(c) && m[c] == t) {
                if (helper(pattern, p + 1, str, i + 1, m)) return true;
            } else if (!m.count(c)) {
                bool b = false;
                for (auto it : m) {
                    if (it.second == t) b = true;
                } 
                if (!b) {
                    m[c] = t;
                    if (helper(pattern, p + 1, str, i + 1, m)) return true;
                    m.erase(c);
                }
            }
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值