First question of debt repayment
Title description
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.
- 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. - 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.
- Initial value
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
Time complexity O(MN)
Space complexity O(MN)