解题思路
这是一道非常巧妙的DP题
s表示string,是一串字符串,p表示pattern,是正则表达式模式。
解题的方法是建立一个二维dp数组,分成 (0,0)单个空、第一行、第一列、其他这4个部分去搞。
假设p的长度是m,s的长度是n,首先创建一个二维数组,长这个样子:
位置1:空字符串"“和空模式”“匹配,直接是true
位置2:字符串"mis"和空模式”“匹配,毫无疑问是false
位置3:空字符串”“和模式"mis"匹配,毫无疑问是false
位置4:字符串"missis"和模式"mis*i"匹配
位置5:字符串"mississippi"和模式"mis*is*p*”,是我们最终需要的答案
对于这个表格来说,第一行和第一列是比较直观好填的(注意这里第一行和第一列都不包括(0,0)这个点):
第一行相当于一个空的模式去匹配一个非空的字符串,结果必然是false:
第一列相当于空的字符串去匹配非空的模式,只有当模式是"x*x*x*…"这种形式时才能匹配上空字符串。例如模式为"a*b*“或者”.*a*"等。
代码为:
for(int i=1;i<=m;i++) {
if(i%2==0) dp[i][0]=((p.charAt(i)=='*')&&dp[i-2][0]);
else dp[i][0]=false;
}
上面的例子处理下来是这样:
中间的部分从上到下从左到右依次处理,位置(i,j)上的值表示模式p的前i个和字符串s的前j个字符进行匹配。这里分情况讨论:
1.p.charAt(i) == s.charAt(j) || p.charAt(i) == '.'
:则dp[i][j]=dp[i-1][j-1]
2.p.charAt(i) == '*'
:
- 2.1
p.charAt(j-1) != s.charAt(j)
:例如xxxa 和 xxxb*匹配,这种情况下,只有这两个红框中的内容相同时才匹配得上:
例如
j | ||
---|---|---|
q | w | e |
i-2 | i | |||
---|---|---|---|---|
q | w | e | b | * |
qwe 和 qweb*可以匹配上,但是qwea和qweb*就匹配不上
此时有dp[i][j]=dp[i-2][j]
- 2.2
p.charAt(j-1) == s.charAt(j)
:这种情况在三种条件下是匹配的:
2.2.1

当dp[i-2][j] == True
时
2.2.2

当dp[i-1][j] == True
时
2.2.3

这种情况下dp[i-1][j]和dp[i-2][j]都为Flase
但此时有dp[i][j-1] == True
即在情况2.2下,有:
dp[i][j] = dp[i-1][j] || dp[i-2][j] || dp[i][j-1]
提交代码
class Solution {
public boolean isMatch(String s, String p) {
if(s==null||p==null) return false;
int n=s.length(),m=p.length();
Boolean[][] dp=new Boolean[m+1][n+1];
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
dp[i][j]=false;
dp[0][0] =true;
for(int i=1;i<=m;i++) {
if(i%2==0) dp[i][0]=((p.charAt(i-1)=='*')&&dp[i-2][0]);
else dp[i][0]=false;
}
for(int j=1;j<=n;j++)
dp[0][j]=false;
for(int i=1;i<=m;i++) {
for(int j=1;j<=n;j++) {
if(s.charAt(j-1)==p.charAt(i-1)||p.charAt(i-1)=='.')
dp[i][j]=dp[i-1][j-1];
else if(p.charAt(i-1)=='*') {
if(p.charAt(i-2)!=s.charAt(j-1)&&p.charAt(i-2)!='.')
dp[i][j]=dp[i-2][j];
else {
dp[i][j]=dp[i-1][j]||dp[i-2][j]||dp[i][j-1];
}
}
}
}
return dp[m][n];
}
}
####运行结果