LeetCode-10 正则表达式匹配
动态规划
10. 正则表达式匹配
dp数组含义:dp[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] ,那么当前字符是匹配成功了,整个子串是否匹配成功取决于之前的子串能否匹配,即 dp[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] 是
.
或*
之外的字符,那肯定不匹配了,dp[i][j]=falsedp[i][j]=falsedp[i][j]=false - 如果 p[j−1]==′.′p[j-1]=='.'p[j−1]==′.′ ,由于
.
可以匹配任何字符,因此当前字符也肯定匹配成功了,还是取决于之前的子串,即 dp[i][j]=dp[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] 匹配零个 sss 中字符,相当于删掉
*
自己及其之前的一个字符,看能不能匹配成功,比如 ### 和 ###a* ,这时 dp[i][j]=dp[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] 匹配一个 sss 中字符,相当于把
*
自己删掉,看能不能匹配成功,比如 ### 和 ###*,这时 dp[i][j]=dp[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] 匹配多个 sss 中字符,这时 dp[i][j]=dp[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] 匹配零个 sss 中字符,相当于删掉
- 如果未能匹配上,即 $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] 删掉,因此就取决于再之前的子串是否匹配:dp[i][j]=dp[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] 是
初始化
首先 dp[0][0]dp[0][0]dp[0][0] 即 sss 和 ppp 均为空时, 认为是可以匹配的,之后的 dp[0][j]dp[0][j]dp[0][j] 要先看 p[j−1]p[j-1]p[j−1] 是否为 *
,若为 *
,则 dp[0][j]=dp[0][j−2]dp[0][j]=dp[0][j-2]dp[0][j]=dp[0][j−2] 。
其他位置均初始化为 falsefalsefalse 。
遍历顺序
从前到后即可
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/