难度: 困难
题目
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式匹配。
-
'.'
匹配任意单个字符 -
'*'
匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖整个字符串 s
的,而不是部分字符串。
示例1
输入:s = "aa" p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例2
输入:s = "aab" p = "c*a*b"
输出:true
解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。
因此可以匹配字符串 "aab"。
解题思路
-
状态: d p [ i + 1 ] [ j + 1 ] dp[i+1][j+1] dp[i+1][j+1] 表示子串 s [ ⋯ i ] s[\cdots i] s[⋯i] 和子串 p [ ⋯ j ] p[\cdots j] p[⋯j] 是否匹配
注意:我们认为字符串s和字符串p开头有一空白字符
-
边界条件
// 第一列 dp[0][0] = true dp[except 0][0] = false // 第一行 if p[j-1] != '*' // p当前字符为字母或者'.' dp[0][j] = false else dp[0][j] = dp[0][j-2]
-
状态转移方程(使用if-else表达):
if (s[i-1] == p[j-1]) or (p[j-1] == '.') dp[i][j] = dp[i-1][j-1] else if p[j-1] == '*' if dp[i][j-2] == true dp[i][j] = true else ((s[i-1] == p[j-2]) or (p[j-2] == '.')) and (dp[i-1][j] == true) dp[i][j] = true else dp[i][j] = false
-
输出:返回 d p [ s . l e n g t h ] [ p . l e n g t h ] dp[s.length][p.length] dp[s.length][p.length] 即为结果
以
s
=
a
a
,
p
=
a
∗
s=aa,\;p=a*
s=aa,p=a∗ 为例,则dp
可表示为下表
空白 | a | * | |
---|---|---|---|
空白 | TRUE | FALSE | TRUE |
a | FALSE | TRUE | TRUE |
a | FALSE | FALSE | TRUE |
难点: 出现'*'
时,要考虑多种情况
代码
// 初始数组全为false,故代码仍可以继续简化
class Solution {
public boolean isMatch(String s, String p) {
int slen = s.length();
int plen = p.length();
boolean[][] dp = new boolean[slen+1][plen+1];
dp[0][0] = true;
// 初始化第一列
for (int i = 1; i < slen + 1; i++) {
dp[i][0] = false;
}
// 初始化第一行
for(int j = 1; j < plen + 1; j++) {
if(p.charAt(j-1) == '*') {
System.out.println(dp[0][j-2]);
dp[0][j] = dp[0][j-2];
} else {
dp[0][j] = false;
}
}
// 转移方程
for(int i = 1; i < slen + 1; i++) {
for(int j = 1; j < plen + 1; j++) {
if (s.charAt(i-1) == p.charAt(j-1) || p.charAt(j-1) == '.') { // 字符相同看左上角
dp[i][j] = dp[i-1][j-1];
} else { // 字符不同
if (p.charAt(j-1) == '*') { // p字符为*
if (dp[i][j-2]) { // 左侧两个为true
dp[i][j] = true;
} else { // 左侧两个为false
if ((p.charAt(j-2) == s.charAt(i-1) || p.charAt(j-2) == '.') && dp[i-1][j] == true) { // 如果p串'*'前的字符与s串当前字符相同 且 dp上侧为true
dp[i][j] = true;
} else { // 其他情况
dp[i][j] = false;
}
}
} else {
dp[i][j] = false;
}
}
}
}
return dp[slen][plen];
}
}