题目介绍
力扣44题:leetcode-cn.com/problems/wi…
分析
解题思路跟 正则表达式匹配 一样。
这就是一个做「选择」的问题,要把所有可能的选择都穷举一遍才能得出结果。动态规划算法的核心就是「状态」和「选择」,「状态」无非就是i和j两个指针的位置,「选择」就是p[j]选择匹配几个字符。
根据「状态」,我们可以定义一个dp函数:
bool dp(string& s, int i, string& p, int j);
dp函数的定义如下:
若dp(s,i,p,j) = true,则表示s[i..]可以匹配p[j..];若dp(s,i,p,j) = false,则表示s[i..]无法匹配p[j..] 。
当p[j]为*通配符时,我们分情况讨论下:
- 如果此时
*是p的最后一个字符,那说明直接可以完全匹配,因为*号可以匹配任意字符串 - 否则 我们可以匹配一个字符,即
dp(s, i + 1, p, j + 1),或者匹配空字符串,即dp(s, i, p, j + 1),又或者继续往下匹配,即dp(s, i + 1, p, j)
代码如下:
class Solution {
public static boolean isMatch(String s, String p) {
return dp(s, 0, p, 0);
}
public static boolean dp(String s, int i, String p, int j) {
int m = s.length();
int n = p.length();
if (n == j) {
return i == m;
}
if (i == m) {
//ab 2
//ab ***
for (; j < n; j += 1) {
if (p.charAt(j) != '*') {
return false;
}
}
return true;
}
// 记录状态 (i, j),消除重叠子问题
String key = i + "," + j;
if (memo.containsKey(key)) {
return memo.get(key);
}
boolean res = false;
if (s.charAt(i) == p.charAt(j) || p.charAt(j) == '?' || p.charAt(j) == '*') {
if (p.charAt(j) == '*') {
//s = cb p = cb* 类似于这种 * 号后面没有了
if (j == p.length() - 1) {
res = true;
} else {
//*可以匹配一个字符,空字符,或者继续往下匹配
res = dp(s, i + 1, p, j + 1) || dp(s, i, p, j + 1) || dp(s, i + 1, p, j);
}
} else {
res = dp(s, i + 1, p, j + 1);
}
} else {
res = false;
}
// 将当前结果记入备忘录
memo.put(key, res);
return res;
}
}