题意
图示:
1. *代表一个字符的情况
2. * 代表一个字符的情况
- * 代表多个字符的情况
解题思路:
思路:
状态定义:dp[i][j] 表示 s 的前 i 个字符是否能被 p 的前 j 个字符匹配
转移方程:
* sc = s[i - 1] pc = p[j - 1]
1. sc == pc|| pc == '.'
1.1 '.'是万能字符,可以直接让'.'等于s[i]处的字符
即:dp[i][j] = dp[i-1][j-1];
2. sc != pc || pc == '*' 分3种情况考虑
2.1 '*'代表0个字符
例子:s:aab, p:aabb*,重复0个b,相当于直接删去j-1(*)和j-2(b),最终要比较的是s(0...i-1)~p(0...j-3)
即:dp[i][j] = dp[i][j-2]
2.2 '*'代表1个字符
例子:s:aab, p:aab* (取1个字符,相当于去掉p[j-1]),只需要比较s(0...i-1)~p(0...j-2)
即:dp[i][j] = dp[i][j-1]
2.2 '*'代表多个字符
例子:s:aab, p:aab* => s:aab, p:aab*b 因为s的最后一个字符b等于p的最后一个字符,可以相互抵消,所以只需要比较 s(0...i-2)~p(0...j-1)即aa跟aab*比较
即:dp[i][j] = dp[i-1][j]
3. sc != pc : 当i,j处是普通字符时,自然不相等
即:dp[i][j] = false
初始化:
1. s,p都为空串时则相匹配=》dp[0,0] = true;
2. s不为空串,模式串p为空串时=》dp[i,0] = false, i >= 1
3. s为空串,模式串p不为空串时,需要考虑p为*号的情况
3.1 如果p最后一个字符p[j-1] == '*',则可以用*把他前面字符重复0次,即消除前面字符,推出=》dp[0, j] = dp[0, j - 2]
3.2 如果p最后一个字符p[j-1] != '*',则不相等,即dp[0, j] = false
PHP代码实现:
class Solution {
function isMatch($s, $p) {
//if ($s == null || $p == null) return false;
$m = strlen($s);
$n = strlen($p);
$dp = array_fill(0, $m + 1, array_fill(0, $n + 1, false));
$dp[0][0] = true;
for ($i = 1; $i <= $m; $i++) $dp[$i][0] = false;
//s为空串,p不是空串的初始化
for ($j = 1; $j <= $n; $j++) {
//$p[$j - 1] == '*',消除j前面的字符
if ($p[$j - 1] == '*') $dp[0][$j] = $dp[0][$j - 2];
else $dp[0][$j] = false;
}
for ($i = 1; $i <= $m; $i++) {
for ($j = 1; $j <= $n; $j++) {
$sc = $s[$i - 1];
$pc = $p[$j - 1];
if ($this->isEqual($sc, $pc)) {
$dp[$i][$j] = $dp[$i - 1][$j - 1];
} else if ($pc == '*') {
$preChar = $p[$j - 2];
if ($this->isEqual($sc, $preChar)) {
$dp[$i][$j] = $dp[$i][$j - 2] || $dp[$i][$j - 1] || $dp[$i - 1][$j];
} else $dp[$i][$j] = $dp[$i][$j - 2];
} else {
$dp[$i][$j] = false;
}
}
}
return $dp[$m][$n];
}
function isEqual($sc, $pc) {
return $sc == $pc || $pc == '.';
}
}
GO代码实现: