剑指 Offer 19-正则表达式匹配C++

还债第一题

题目描述

在这里插入图片描述
在这里插入图片描述

解法 dp

做过几题dp的话,应该可以猜测出dp方程的含义,但是dp方程以及初始化都是本题的难点。

  1. dp数组含义
    dp[i][j] : s的前i个字符和p的前j个字符是否可以匹配。可见只有两种取值,但是经验告诉我们,用int比bool快。
  2. dp方程
    也就是本题最难的地方了,我们观察的角度是从p的最后一个字符出发(怎么想到从p的最后一个字符出发呢?这就是和大佬实力的差距了 )。分为三种情况
  • 该字符为普通字母,我们需要看s[j - 1]与p[i - 1]是否相等,相等则看dp[i - 1] [j - 1]
  • 该字符为 ’ - ',只需要看dp[i - 1] [j - 1]
  • 该字符为 ’ * ’ ,这时我们又有两种情况,一种是p[j - 2] 与 s[i - 1]不相等,这时我们可以忽视 ’ * ’ 以及前面的那个字符-----视为取0个该字符,dp[i][j] = dp[i][j - 2];第二种是p[j - 2] 与 s[i - 1]相等,这时我们可以选择对 ‘*’ 前面的字符和s进行匹配,或者不匹配。
    这里要非常注意,*可以取代任意数量的字符,但是取越多并不是好事,不匹配的情况才能保证取到一定数量的字符就停止。
  1. 初始值
    在这里插入图片描述
    这里有个特殊的技巧,将dp的行和列的长度多加1,这样能方便讨论空串的情况:即dp[0][n]和dp[n][0]
class Solution {
    
    
public:
    bool isMatch(string s, string p) {
    
    
        int len1 = s.size();
        int len2 = p.size();
        vector<vector<int>> dp(s.size() + 1,vector<int>(p.size() + 1, 0));
        //dp[i][j]:s[:i - 1] p[:j - 1]匹配
        for(int i = 0; i <= len1; i++)
            for(int j = 0; j <= len2; j++) {
    
    
                if(j == 0) {
    
    
                    dp[i][j] = i == 0 ? 1 : 0;
                }
                else {
    
    
                    if(p[j - 1] != '*') {
    
    
                        //i > 0说明s[:i - 1]非空 如果为空则此位必错
                        if(i > 0 && (p[j - 1] == s[i - 1] || p[j - 1] == '.')) 
                            dp[i][j] = dp[i - 1][j - 1];
                    }
                    //p[j - 1] =='*' 注意两者择一即可,不是你死我活的关系
                    else {
    
    
                        //假设*的前一位不匹配的情况
                        if(j >= 2) 
                            dp[i][j] |= dp[i][j - 2];
                        //*的前一位匹配的情况
                        if(i > 0 && j >=2 && (s[i - 1] == p[j - 2] || p[j - 2] == '.'))
                        //这里或等于很重要,防止把不使用*的情况覆盖,有时候即使可以匹配不使用才是对的
                            dp[i][j] |= dp[i - 1][j];
                    }
                }
                cout<<"["<<i<<"]"<<"["<<j<<"]"<<"="<<dp[i][j]<<endl;
            }
        return dp[len1][len2];
    }
};

关于*的情况再举一个例子
比如
“a a a”
“a b * a * c * a”
这里的dp[3][8] = dp[2][7] = dp[2][5]
dp[2][5] 的情况下
“a a”
"a b * a * "
如果我们只选择用a来匹配,
dp[2][5]= dp[1][5] = dp[0][5] = dp[0][3] = dp[0][1] = 0很明显得到了错误答案
但是如果我们选择可以忽视a
dp[2][5] = dp[1][5] = dp[1][3] = dp[1][1] = 1 得到正确的答案
在这里插入图片描述
时间复杂度O(MN)
空间复杂度O(MN)

猜你喜欢

转载自blog.csdn.net/qq_42883222/article/details/112972712
今日推荐