一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情
题目描述
思路
- 很明显这道题解题思路就是动态规划。因为想要判断d[i][j]那么势必需要考虑d[i-1][j-1]的情况。这和我们之前说动态规划的时候思路是一致的。我们需要确定初始状态然后在确定变化方程以及边界就可以了。
- 字符串类题目常用方法是状态机、动态规划、双指针的方法,IF-ELSE 写法对于字符串类题目非常不友好。对于匹配类题目,通常我们用动态规划来解决。
patter[j] == '*' 遇到 * 就要把它和前面看作一个整体,根据规则,它们有以下三种能力:
匹配零次:忽略这个组合,S(i)S(i) 和 P(j - 2)P(j−2) 能匹配的话就 OK,即
if (dp[i][j - 2])
dp[i][j] = true;
正常情况下 ii 行 jj 列的 dp 数组,需要处理上面的特殊情况和写一堆判断是否处于开头的代码,因此我们增加一个初始行和初始列,简化代码简化逻辑。
第 0 列:代表模式串与 SS 前面的 "" 进行匹配,此时 ab 匹配 "" 我们判定为 true 就 OK。
第 0 行:由于匹配需要看 dp[i - 1][j - 1],为了方便编码我们引入第 0 行,代表 SS 与 PP 前面的 "" 进行匹配,此时 dp[0][0] 代表 "" 与 "" 的匹配,为 true。
但是我们还需要考虑一下特殊情况,就是我们匹配字符串时并没有生效。这个时候我们又改怎么做呢。这就是对应我们动态规划套路中的确定初始状态。确定初始状态之后我们就可以进行推到了
AC
public boolean isMatch(String s, String p) {
if (s == null || p == null) return false;
int m = s.length(), n = p.length();
if (m == 0 && n == 0) return true;
if (n == 0) return false;
boolean[][] dp = new boolean[m + 1][n + 1];
char[] string = s.toCharArray();
char[] pattern = p.toCharArray();
dp[0][0] = true;
for (int i = 1; i < dp[0].length; i++) {
if (pattern[i - 1] == '*')
dp[0][i] = dp[0][i - 2];
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if (string[i - 1] == pattern[j - 1] || pattern[j - 1] == '.') {
dp[i][j] = dp[i - 1][j - 1];
} else if (pattern[j - 1] == '*') {
// 匹配零次
dp[i][j] |= dp[i][j - 2];
// 匹配一次
dp[i][j] |= dp[i][j - 1];
// 匹配多次
dp[i][j] |= dp[i - 1][j] && (string[i - 1] == pattern[j - 2] || pattern[j - 2] == '.');
}
}
}
return dp[string.length][pattern.length];
}