力扣10:正则表达式的匹配——动态规划

**

力扣10:正则表达式的匹配——动态规划

**

题目:给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 . 和 * 的正则表达式匹配。
" . " 匹配任意单个字符
" * " 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1
输入:s = “aa” p = “a”
输出:false
解释:“a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:s = “aa” p = “a*”
输出:true
解释:因为 ‘’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3
输入:s = “ab” p = ".
"
输出:true
解释:"." 表示可匹配零个或多个(’’)任意字符(’.’)。
示例 4
输入:s = “aab” p = “cab”
输出:true
解释:因为 '’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5
输入:s = “mississippi” p = "mis
isp."
输出:false
提示
0 <= s.length <= 20
0 <= p.length <= 30
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符

解题思路:一开始的思路是想从左往右匹配,但因为不知道重复的字母会有几个并且字符后面是否会有*也会影响结果,所以分析起来过于复杂。于是采用从右往左的解决思路。
而s的第i个与p的第j个是否匹配取决于两点
1.第i个和第j个是否匹配
2.s的前i-1个和p的前j-1个子串是否匹配
于是可以采用动态规划的思想。将一个问题划分为若干个子问题。
用bool型二维数组dp[n][m]来储存结果。(dp[i][j]==true表示s[0,i-1]和p[0,j-]的字符串匹配
然后开始分情况讨论:
1.当p[j-1] == s[i-1]时,这时dp[i][j]取决于前一个字符串是否匹配上,所以dp[i][j] = dp[i-1][j-1].(p[j-1],s[i-1]储存的是p的第j个字符和s的第i个字符)
2.当p[j-1] == '.'时,p[j-1]与s的任意字符都匹配,所以dp[i][j] = dp[i-1][j-1].
3.当p[j-1] == ’ * '时,又要分两种情况讨论:
(1)p[j-2]与s[i-1]不匹配,这时要将p[j-2]消掉,所以dp[i][j]=d[i][j-2];
(2)p[j-2]与s[i-1]匹配,这时可能是单个字符匹配,多个字符匹配,或者没有匹配的情况。所以dp[i][j]分别等于dp[i][j-1],dp[i-1][j],dp[i][j-2].

另外需要考虑边界条件:
1.s,p都是空串的时候,这时s,p是匹配的,所以dp[0][0]=true.
2.s是空串而p不是空串时,这时p要想匹配只能是p的右端是 * 然后干掉一个字符,如此往复直到p为空串。
3.s不是空串而p是空串时,一定不匹配。
代码C++

bool isMatch(string s, string p)//动态规划,dp[i][j]表示s[0,i-1]的字符与p[0][j-1]的字符匹配
{
    int n1 = s.size();
    int n2 = p.size();
    bool dp[n1 + 1][n2 + 1];
    memset(dp, false, (n1 + 1) * (n2 + 1));//初始化都为false
    dp[0][0] = true;//都是空串时匹配
    if (!s.empty() && p.empty())//s不是空串而p是空串时,一定不匹配
        return false;
    for (int i = 1; i <= n2; i++)//s是空串时,p的第i个字符是 *,则它的状态取决于第i-2个字符的状态,也就是说第i个字符是 * 号则干掉它前一个字符和它自己。
    {
        if (p[i - 1] == '*')
            dp[0][i] = dp[0][i - 2];
    }

    for (int i = 1; i <= n1; i++)
        for (int j = 1; j <= n2; j++)
        {
            if (s[i - 1] == p[j - 1])
            {
                dp[i][j] = dp[i - 1][j - 1];
            }
            else if (p[j - 1] == '.')
            {
                dp[i][j] = dp[i - 1][j - 1];
            }
            else if (p[j - 1] == '*')
            {
                if (p[j - 2] == s[i - 1] || (p[j - 2] == '.'))
                {
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];
                }
                else
                {
                    dp[i][j] = dp[i][j - 2];
                }
            }
        }
    return dp[n1][n2];
}

因为笔者水平有限,所以文章中难免会出现错误或者不足的地方,望大家斧正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值