Sword refers to Offer 19-regular expression matching C++

First question of debt repayment

Title description

Insert picture description here
Insert picture description here

Solution dp

If you have done a few dp questions, you should be able to guess the meaning of the dp equation, but the dp equation and initialization are the difficulties of this question.

  1. The meaning of dp array
    dp[i][j]: Whether the first i characters of s and the first j characters of p can match . It can be seen that there are only two values, but experience tells us that using int is faster than bool.
  2. The dp equation is
    also the most difficult part of this question. Our observation angle is to start from the last character of p (how do we think of starting from the last character of p? This is the gap between the strength of the boss ). Divided into three situations
  • The character is an ordinary letter, we need to see whether s[j-1] and p[i-1] are equal, and if they are equal, see dp[i-1] [j-1]
  • The character is'-', just look at dp[i-1] [j-1]
  • The character is' *'. At this time, we have two situations. One is that p[j-2] and s[i-1] are not equal. At this time, we can ignore the '*' and the previous character - --- Treated as taking 0 of the character, dp[i][j] = dp[i][j-2]; the second is that p[j-2] is equal to s[i-1], then We can choose to match the character before'*' and s, or not.
    It is important to note here that * can replace any number of characters, but it is not a good thing to take more characters. Only in the case of mismatch can it be guaranteed to stop when a certain number of characters are taken.
  1. Initial value
    Insert picture description here
    There is a special trick to increase the length of dp's row and column by 1 to facilitate the discussion of the empty string: namely dp[0][n] and 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];
    }
};

Let’s take another example for the case of *. For
example,
"aaa"
"ab * a * c * a"
where dp[3][8] = dp[2][7] = dp[2][5]
dp[2] In the case of [5]
"aa"
"ab * a * "
If we only choose a to match,
dp[2][5] = dp[1][5] = dp[0][5] = dp[ 0][3] = dp[0][1] = 0 Obviously we got the wrong answer,
but if we choose, we can ignore a
dp[2][5] = dp[1][5] = dp[1][3 ] = dp[1][1] = 1 Get the correct answer
Insert picture description here
Time complexity O(MN)
Space complexity O(MN)

Guess you like

Origin blog.csdn.net/qq_42883222/article/details/112972712