题目描述
给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符。'*' 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。
说明:
s可能为空,且只包含从a-z的小写字母。p可能为空,且只包含从a-z的小写字母,以及字符.和*。
示例 1:
输入:s = "aa"p = "a"输出: false解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa"p = "a*"输出: true解释: '*' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 "aa"。
示例 3:
输入:s = "ab"p = ".*"输出: true解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入:s = "aab"p = "c*a*b"输出: true解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入:s = "mississippi"p = "mis*is*p*."输出: false
题解
DP
参考:Java DP solution beats %100 with explanation 👍
用 dp[i,j] 表示 s.Substring(0,i) 是否可以用 p.Substring(0,j) 匹配。例如 dp[0,0] = true,因为当 s 和 p 都是空时它们相匹配。
s='aab', p='c*a*b'c * a * b0 1 2 3 4 50 ya 1a 2b 3
针对第一列 p = “” 只有字符串 s = “” 与它匹配,那就是 dp[0,0],这也意味着第一列除了 dp[0,0] 都是 false。
s='aab', p='c*a*b'c * a * b0 1 2 3 4 50 ya 1 na 2 nb 3 n
针对第一行 s = “”,p = “” 或 p =”a“(任意字符) 都能与它匹配,甚至 p = “abc*” 都能与其匹配。下面就是循环填充第一行的代码:
for (int j=2; j<=p.length(); j++){dp[0][j] = p.charAt(j-1) == '*' && dp[0][j-2];}
处理完第一行和第一列后我们的矩阵就变成了:
注意因为 p = “c“ 和 p=”ca*” 都能匹配空字符串,所以 dp[0,2] 和 dp[0,4] 是 true。
s='aab', p='c*a*b'c * a * b0 1 2 3 4 50 y n y n y na 1 na 2 nb 3 n
现在我们可以开始主循环了。分两种情况:
p[j-1] == s[i-1] || p[j-1] == '.':如果当前字符相同或表达式是.那匹配与否由之前的状态决定dp[i,j] = dp[i-1,j-1]。之所以索引都是 i-1,j-1 有 -1 的偏移,是因为我们的 dp 数组尺寸比字符串大 1,以保存初始状态dp[0,0]如果
p[j-1] == '*'那么可以将它视为一个空集,dp[i,j]等于dp[i,j-2]或(s[i-1] p[j-2] || p[j-2] == '.')。又因为当前的字符需要与表达式 * 之前的字符相匹配,所以还需要与dp[i-1,j]
于是最终的 dp 矩阵如下:
s='aab', p='c*a*b'c * a * b0 1 2 3 4 50 y n y n y na 1 n n n y y na 2 n n n n y nb 3 n n n n n y
DP 代码:
public bool IsMatch(string s, string p){if (string.IsNullOrEmpty(p)) return string.IsNullOrEmpty(s);var dp = new bool[s.Length + 1, p.Length + 1];dp[0, 0] = true;for (var j = 2; j <= p.Length; j++){dp[0, j] = p[j - 1] == '*' && dp[0, j - 2];}for (var j = 1; j <= p.Length; j++){for (var i = 1; i <= s.Length; i++){if (p[j - 1] == s[i - 1] || p[j - 1] == '.'){dp[i, j] = dp[i - 1, j - 1];}else if (p[j - 1] == '*'){dp[i, j] = dp[i, j - 2] || ((s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1, j]);}}}return dp[s.Length, p.Length];}
时间和空间复杂度都是 O(p.Length * s.Length)。
