10. 正则表达式匹配
思路解析
这道题虽然看起来不难理解,但却存在多种可能,当然这种可能的数量是有限的,且其规律对于每一次判别都使用,所以自然而然就想到用 动态规划 的方法啦
接下来逐步分析可能的情况:
(s1 为 字符串 的字符数组(长度m),s2 为匹配规律的字符数组(长度n)
由于需要存储每次匹配是否成功的结果,所以需构造一个二维布尔数组,存放对应是否匹配成功
s2 的 每一个匹配字符有三种情况:正常字符、'.' 、'*', 所以可以以此分类
1. 如果s2[n-1] 是正常字符(不是'.' 或 ‘*’) , 则如果 s1[m-1] = s2[n-1], 这时如果前面都匹配成功,则该次也匹配成功,即取决于 s1[0...m-2] 和 s2[0...n-2]是否匹配,否则不能匹配。
2. 如果s2[n-1] 是 '.' 即可满足任意字符,则 s1[m-1] 一定和 '.' 匹配, 这时如果前面匹配成功,即
s1[0...m-2] 和 s2[0...n-2] 都匹配,则该次匹配成功。
3. 如果 s2[n-1] 是 '*' ,则s2[n-2]='x' 可以重复0次或多次,这时s2[n-2]和s2[n-1]为一个整体X,这时会出现两种情况,即s1[m-1] 是 0个字符'x',还是多个'x'中的最后一个
i. 如果s1[m-1]是0个字符'x', 则s1[m-1]与s2的匹配规则整体X无关,这时只需看s1[0...m-1] 和 s2[0...n-3]是否匹配即可。
ii. 如果s1[m-1]是多个'x'的最后一个, 则这时候s1[m-1]必须为'x' 或者 s2[n-2] 为’.' 任意字符, 满足该条件后能否匹配则看 s1[0...m-2] 和 s2[0....n-1] 是否匹配。
初始条件和边界情况:空串和空正则表达式匹配:f[0][0] = TRUE
代码详解
话不多说,上代码
class Solution {
// 动态规划
public boolean isMatch(String s, String p) {
char[] s1 = s.toCharArray();
char[] s2 = p.toCharArray();
int m = s1.length;
int n = s2.length;
boolean[][] f = new boolean[m+1][n+1];
for(int i = 0; i <= m; i++) {
// 边界情况:空串和空正则表达式匹配
f[i][0] = (i==0);
for(int j = 1; j <= n; j++) {
f[i][j] = false;
// 不为'*'的情况: 则当s2[j-1]为任意字符'.' 或者s2[j-1]==s1[i-1]满足
if(s2[j-1] != '*') {
if(i > 0 && (s2[j-1]=='.' || s2[j-1]==s1[i-1])){
// 按位或,若 f[i-1][j-1]为true,则f[i][j]为true
f[i][j] |= f[i-1][j-1];
}
} else {
// 为s2[j-1]'*'的情况:
// 如果s1[i-1]为0个匹配字符, 那么f[i][j] 是否为true取决与 f[i][j-2], 即s1第i-1和s2第j-3比较
if(j - 2 >= 0) {
f[i][j] |= f[i][j-2];
}
// s2[j-2]=='.' 或者 s1[i-1]==s2[j-2]
// 则 那么f[i][j] 是否为true取决与 f[i-1][j], 此时i必满足,所以看i-1
if(i>0 && j -2 >= 0 && (s2[j-2]=='.' || s1[i-1]==s2[j-2])){
f[i][j] |= f[i-1][j];
}
}
}
}
return f[m][n];
}
}