【Leetcode】10. 正则表达式匹配 【字符串、动态规划】

给定一个字符串 (sss) 和一个字符模式 (ppp)。实现支持 ‘...’ 和 ‘∗*’ 的正则表达式匹配。

...’ 匹配任意单个字符。
∗*’ 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (sss) ,而不是部分字符串。

说明:

sss 可能为空,且只包含从 a−za-zaz 的小写字母。
ppp 可能为空,且只包含从 a−za-zaz 的小写字母,以及字符 ...∗*
示例 111:

输入:s = “aaaaaa
p = “aaa
输出: falsefalsefalse
解释: “aaa” 无法匹配 “aaaaaa” 整个字符串。
示例 222:

输入:
sss = “aaaaaa
ppp = “a∗a*a
输出: truetruetrue
解释: ‘∗*’ 代表可匹配零个或多个前面的元素, 即可以匹配 ‘aaa’ 。因此, 重复 ‘aaa’ 一次, 字符串可变为 “aaaaaa”。
示例 333:

输入:
sss = “ababab
ppp = “.∗.*.
输出: truetruetrue
解释: “.∗.*.” 表示可匹配零个或多个(’∗*’)任意字符(’...’)。
示例 444:

输入:
sss = “aabaabaab
ppp = “c∗a∗bc*a*bcab
输出: truetruetrue
解释: ‘ccc’ 可以不被重复, ‘aaa’ 可以被重复一次。因此可以匹配字符串 “aabaabaab”。
示例 555:

输入:
sss = “mississippimississippimississippi
ppp = “mis∗is∗p∗.mis*is*p*.misisp.
输出: falsefalsefalse

思路:

1)递归。

  • 如果ppp的下一个字符为∗*,那么(1)(1)(1)sss不为空且p[0]=s[0]p[0] = s[0]p[0]=s[0]p[0]=′.′p[0] = '.'p[0]=.,即该位能够匹配时,那么这个时候由于∗*可以匹配多个前面字符,则递归描述为(s+1,p)(s + 1, p)(s+1,p),在这里采取截取字符串的方式,(s.substr(1),p)(s.substr(1), p)(s.substr(1),p) (2)(2)(2)当不满足(1)(1)(1)条件时,则递归描述为(s,p.substr(2))(s, p.substr(2))(s,p.substr(2))
  • 如果ppp的下一个字符不为∗*,那么只有两个字符匹配,即sss不为空且p[0]=s[0]p[0] = s[0]p[0]=s[0]p[0]=′.′p[0] = '.'p[0]=.成立时,才能继续匹配下一个字符,递归描述为(s.substr(1),p.substr(1))(s.substr(1), p.substr(1))(s.substr(1),p.substr(1))
class Solution {
public:
    bool isMatch(string s, string p) {
        if (p.empty()) return s.empty();
        if (p.size() > 1 && p[1] == '*') {
        	//两种匹配方式
            return isMatch(s, p.substr(2)) || 
            (!s.empty() && (s[0] == p[0] || p[0] == '.') 
            && isMatch(s.substr(1), p));
        } else {
        	//满足前面条件才能继续匹配
            return !s.empty() && (s[0] == p[0] || 
            p[0] == '.') && isMatch(s.substr(1), p.substr(1));
        }
    }
};

2)动态规划。实则对上述递归表达的解析。

  • dp[i][j]=truedp[i][j] = truedp[i][j]=true描述为sss中前iii个字符与ppp中前jjj个字符匹配
  • 如果p[j−1]=′∗′p[j - 1] = '*'p[j1]=,那么对应上述的第1)1)1)种情况,则有dp[i][j]=dp[i][j−2]dp[i][j] = dp[i][j - 2]dp[i][j]=dp[i][j2] || (i>0i > 0i>0 && (s[i−1]==p[j−2]∣∣p[j−2]==′.′s[i - 1] == p[j - 2] || p[j - 2] == '.'s[i1]==p[j2]p[j2]==. ) && dp[i−1][j]dp[i - 1][j]dp[i1][j],即将上述的分析逆转一下
  • 如果p[j - 1] != ‘*’,那么对应上述的第2)种情况,则有$dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.
class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size(), n = p.size();
        bool dp[m + 1][n + 1];
        memset(dp, false, sizeof(dp));
        dp[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (j > 1 && p[j - 1] == '*') {
                    dp[i][j] = dp[i][j - 2] || (i > 0 && (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);
                } else {
                    dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.');
                }
            }
        }
        return dp[m][n];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值