LeetCode-10 正则表达式匹配
动态规划
dp数组含义: d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 s [ 0 : i − 1 ] s[0:i-1] s[0:i−1] 能否被 p [ 0 : j − 1 ] p[0:j-1] p[0:j−1] 成功匹配。
状态转移方程 :
- 如果 s [ i − 1 ] = = p [ j − 1 ] s[i-1]==p[j-1] s[i−1]==p[j−1] ,那么当前字符是匹配成功了,整个子串是否匹配成功取决于之前的子串能否匹配,即 d p [ i ] [ j ] = d [ i − 1 ] [ j − 1 ] dp[i][j]=d[i-1][j-1] dp[i][j]=d[i−1][j−1] 。
- 如果
s
[
i
−
1
]
≠
p
[
j
−
1
]
s[i-1]\ne p[j-1]
s[i−1]=p[j−1] ,可以按
p
[
j
−
1
]
p[j-1]
p[j−1] 是什么分三种情况:
- 如果
p
[
j
−
1
]
p[j-1]
p[j−1] 是
.
或*
之外的字符,那肯定不匹配了, d p [ i ] [ j ] = f a l s e dp[i][j]=false dp[i][j]=false - 如果
p
[
j
−
1
]
=
=
′
.
′
p[j-1]=='.'
p[j−1]==′.′ ,由于
.
可以匹配任何字符,因此当前字符也肯定匹配成功了,还是取决于之前的子串,即 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j]=dp[i-1][j-1] dp[i][j]=dp[i−1][j−1] 。 - 如果
p
[
j
−
1
]
=
=
′
∗
′
p[j-1]=='*'
p[j−1]==′∗′ ,情况比较复杂,需要再看
p
[
j
−
2
]
p[j-2]
p[j−2] 与
s
[
i
−
1
]
s[i-1]
s[i−1] 的关系,因为
p
[
j
−
2
]
p[j-2]
p[j−2] 要与
s
[
i
−
1
]
s[i-1]
s[i−1] 匹配上,
p
[
j
−
1
]
p[j-1]
p[j−1] 的这个
*
才有用- 而所谓 ”匹配上“,可能有两种情况,一个是字符相同,即
p
[
j
−
2
]
=
s
[
i
−
1
]
p[j-2]=s[i-1]
p[j−2]=s[i−1];另一个是
p
[
j
−
2
]
p[j-2]
p[j−2] 是
.
,匹配任意字符。可以再按照 p [ j − 1 ] p[j-1] p[j−1] 这个*
让 s [ i − 1 ] s[i-1] s[i−1] 这个字符出现几次来分,零次、一次或两次及以上:-
p
[
j
−
1
]
p[j-1]
p[j−1] 匹配零个
s
s
s 中字符,相当于删掉
*
自己及其之前的一个字符,看能不能匹配成功,比如 ### 和 ###a* ,这时 d p [ i ] [ j ] = d p [ i ] [ j − 2 ] dp[i][j]=dp[i][j-2] dp[i][j]=dp[i][j−2] ; -
p
[
j
−
1
]
p[j-1]
p[j−1] 匹配一个
s
s
s 中字符,相当于把
*
自己删掉,看能不能匹配成功,比如 ### 和 ###*,这时 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 2 ] dp[i][j]=dp[i-1][j-2] dp[i][j]=dp[i−1][j−2] ; - p [ j − 1 ] p[j-1] p[j−1] 匹配多个 s s s 中字符,这时 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
- 注意,以上三种情况只要满足一种即可,是 或 的关系。
-
p
[
j
−
1
]
p[j-1]
p[j−1] 匹配零个
s
s
s 中字符,相当于删掉
- 如果未能匹配上,即 $p[j-2]\ne s[i-1] $ 且
p
[
j
−
2
]
≠
′
.
′
p[j-2]\ne '.'
p[j−2]=′.′ ,这时
p
[
j
−
1
]
p[j-1]
p[j−1] 的这个
*
可以把没能匹配上的 p [ j − 2 ] p[j-2] p[j−2] 删掉,因此就取决于再之前的子串是否匹配: d p [ i ] [ j ] = d p [ i ] [ j − 2 ] dp[i][j]=dp[i][j-2] dp[i][j]=dp[i][j−2] 。
- 而所谓 ”匹配上“,可能有两种情况,一个是字符相同,即
p
[
j
−
2
]
=
s
[
i
−
1
]
p[j-2]=s[i-1]
p[j−2]=s[i−1];另一个是
p
[
j
−
2
]
p[j-2]
p[j−2] 是
- 如果
p
[
j
−
1
]
p[j-1]
p[j−1] 是
初始化
首先
d
p
[
0
]
[
0
]
dp[0][0]
dp[0][0] 即
s
s
s 和
p
p
p 均为空时, 认为是可以匹配的,之后的
d
p
[
0
]
[
j
]
dp[0][j]
dp[0][j] 要先看
p
[
j
−
1
]
p[j-1]
p[j−1] 是否为 *
,若为 *
,则
d
p
[
0
]
[
j
]
=
d
p
[
0
]
[
j
−
2
]
dp[0][j]=dp[0][j-2]
dp[0][j]=dp[0][j−2] 。
其他位置均初始化为 f a l s e false false 。
遍历顺序
从前到后即可
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size(), n = p.size();
vector<vector<bool>> dp(m+1, vector<bool> (n+1, false));
dp[0][0] = true;
for (int j=1; j<n+1; ++j) {
if (p[j-1] == '*') dp[0][j] = dp[0][j-2];
}
for (int i=1; i<m+1; ++i) {
for (int j=1; j<n+1; ++j) {
if (s[i-1] == p[j-1] || p[j-1] == '.') dp[i][j] = dp[i-1][j-1];
else if (p[j-1] == '*') {
if (s[i-1] == p[j-2] || p[j-2] == '.') {
dp[i][j] = dp[i][j-2] || dp[i-1][j-2] || dp[i-1][j];
}
else {
dp[i][j] = dp[i][j-2];
}
}
}
}
return dp[m][n];
}
};
Ref:
https://leetcode.cn/problems/regular-expression-matching/solution/shou-hui-tu-jie-wo-tai-nan-liao-by-hyj8/
https://leetcode.cn/problems/regular-expression-matching/solution/dong-tai-gui-hua-zen-yao-cong-0kai-shi-si-kao-da-b/