LintCode 192: Wildcard Matching (经典题)

这题有三个解法:

  1. DFS 深搜 + memorization
  2. DP
  3. Greedy
    另外,是否可能也可以用BFS做呢?
    网上的这个链接不错:
    https://blog.csdn.net/wrm_nancy/article/details/51296416

解法1:
注意:

  1. s或p为空时不能返回false,因为有可能s=“”, p=“*”,此时应返回true。
  2. memorization 包括visited和memo这两个字段。为什么需要memo字段呢? 这是因为’*‘也可以表示空字符。假设s=“aab”, p=“a?*b”:
    vm[0][0].memo = true
    vm[1][1].memo = true
    vm[2][2].memo = ? needs vm[2][3]
    vm[2][3].memo = true,因为都是’b’
    我们可以看到vm[2][2]提前用到了vm[2][3],这样,当后来计算vm[2][3]时就可以以直接返回结果了。
class visitedMemo {
public:
    bool visited;
    bool memo;
    visitedMemo(bool v = false, bool m = false) : visited(v), memo(m) {}
};


class Solution {
public:
    /**
     * @param s: A string 
     * @param p: A string includes "?" and "*"
     * @return: is Match?
     */
    bool isMatch(string &s, string &p) {
        //if (s.empty() || p.empty()) return false;
        //define vm[s.size()][p.size()]
        vector<vector<visitedMemo>> vm;
        vm.resize(s.size(), vector<visitedMemo>(p.size()));   
        
        return helper(s, 0, p, 0, vm); 
    }
    
    bool helper(string const &s, int sIndex, string const &p, int pIndex, vector<vector<visitedMemo>> &vm) {
        
        // if p reachees the end (pos is the last char + 1) first, s should also reaches the end
        if (pIndex  == p.size()) {
            return (sIndex == s.size());    
        }
        
        // if s reaches the end first, then p[pIndex..end] should be all *, 
        // for example, s = "ab", p = "a****"
        if (sIndex == s.size()) {
            for (int i = pIndex; i < p.size(); ++i) {
                if (p[i] != '*') return false;
            }
            return true;
        }
        
        if (vm[sIndex][pIndex].visited) return vm[sIndex][pIndex].memo;
        
        vm[sIndex][pIndex].visited = true;
        if (p[pIndex] == '*') {
            vm[sIndex][pIndex].memo = helper(s, sIndex + 1, p, pIndex, vm) ||
                                      helper(s, sIndex, p, pIndex + 1, vm);
        } else {
            if ((s[sIndex] == p[pIndex]) || (p[pIndex] == '?'))
                vm[sIndex][pIndex].memo = helper(s, sIndex + 1, p, pIndex + 1, vm);
            else
                vm[sIndex][pIndex].memo = false;
        }
        
        return vm[sIndex][pIndex].memo;
    }
    
    
};

解法2: DP
注意:

  1. s和p都先加一个’a’,这样不影响结果正确性,而且对s="b"和p="b*"这样的情况比较好处理。因为如果不加’a’的话,dp[1][1]=true后,i = 1, j = 2时,因为dp[i-1][j-1]还是false,所以最终结果dp[1][2]还是false。
    但是加了’a’后,s=“ba”, p=“b*a”, dp[1][1]=true后,i=2,j=2时,bp[1][2]和bp[2][2]都为true (实际上到这里就够了)。然后i=2,b=3时,bp[2][3]会用到bp[1][2]的结果,也为true.
  2. 下面这个DP的方法讲得非常好。不过我的解法是i循环管s,j循环管p。他的解法是i循环管p, j循环管s。因为实际上s比p要多跑一些字符,因为p有*和?。
    https://www.lintcode.com/problem/192/solution/56425
class Solution {
public:
    bool isMatch(string s, string p) {
        s = s + 'a';
        p = p + 'a';
        int m = s.size();
        int n = p.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        dp[0][0] = true;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (dp[i][j]) continue;
                if (p[j - 1] == '*') {
                    if (dp[i - 1][j - 1]) {
                        for (int k = i - 1; k <= m; k++) dp[k][j] =  true;
                    }
                }
                else if (p[j - 1] == '?') {
                    dp[i][j] = dp[i - 1][j - 1];
                } 
                else if (dp[i - 1][j - 1] && s[i - 1] == p[j - 1]) {
                    dp[i][j] = true;
                }
            }
        }
        return dp[m][n];
    }
};

解法3:还是DP。只是第1维和第2维反过来。这样可以方便用Passthru。不需要再加一个循环。不过其实解法2再加一个循环也没有影响复杂度。

class Solution {
public:
    bool isMatch(string s, string p) {
        s = s + 'a';
        p = p + 'a';
        int m = s.size();
        int n = p.size();
        vector<vector<bool>> dp(n + 1, vector<bool>(m + 1, false));
        dp[0][0] = 1;

        for (int i = 1; i <= n; i++) {
            bool passthru = false;
            for (int j = 1; j <= m; j++) {
                if (dp[i - 1][j - 1] && p[i - 1] == '*') {
                    passthru = true;
                    dp[i][j - 1] = true;
                } else if (dp[i - 1][j - 1]) {
                    if (p[i - 1] == '?' || s[j - 1] == p[i - 1]) {
                        dp[i][j] = true;
                    }
                }
                if (passthru) {
                    dp[i][j] = true;
                }

            }
        }
        return dp[n][m];
    }
};

解法4: Greedy
下次做。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值