给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符序列(包括空字符序列)。
判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。
示例 1:
输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa", p = "*"
输出:true
解释:'*' 可以匹配任意字符串。
示例 3:
输入:s = "cb", p = "?a"
输出:false
解释:'?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
0 <= s.length, p.length <= 2000
s 仅由小写英文字母组成
p 仅由小写英文字母、'?' 或 '*' 组成
解题思路:
1、例 s = "accba",p = "a?c*", 准备一个6 * 5 的网格
2、先看basecase grid[0][0] 0行0列的含义是一个空字符串匹配一个空字符串一定是可以匹配成功的,所以该位置必为T
3、再来看第一列,第一列的含义是原始字符串为空,如果要匹配成功,p 只能为"*" ,所以从第一个不为*的格子开始标F
4、在来看第一行(除[0][0]位置以外)的含义,用空字符串去匹配一个非空字符串,所以都是F
4、再来看普遍位置的情况。如果p中的字符是a~z,则必须与s中字符一样才行,并且grid[i-1][j-1]需要匹配得上
5、如果p中字符是?,则只要grid[i-1][j-1]匹配的上就行
6、如果p中字符是*,则grid[i-1][j-1],grid[i][j-1]和grid[i-1][j]只要有一个匹配得上就行
Java代码
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[n+1][m+1];
dp[0][0] = true;
for(int i=1; i<=p.length(); i++){
if(p.charAt(i-1)=='*'){
dp[i][0] = dp[i-1][0] ? true : false;
}else{
dp[i][0] = false;
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(p.charAt(i-1)!='*'&&p.charAt(i-1)!='?'){
if(p.charAt(i-1)==s.charAt(j-1)){
dp[i][j] = dp[i-1][j-1] ? true : false;
}
}else if(p.charAt(i-1)=='?'){
dp[i][j] = dp[i-1][j-1] ? true : false;
}else if(p.charAt(i-1)=='*'){
dp[i][j] = dp[i-1][j-1] | dp[i-1][j] | dp[i][j-1];
}
}
}
return dp[n][m];
}
}
Python代码
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
m = len(s)
n = len(p)
dp = [[False for _ in range(m+1)] for _ in range(n+1)]
dp[0][0] = True
for i in range(1, len(p)+1):
if p[i-1] == '*':
if dp[i-1][0]:
dp[i][0] = True
else:
dp[i][0] = False
for i in range(1, n+1):
for j in range(1, m+1):
if p[i-1] != '*' and p[i-1] != '?':
if p[i-1] == s[j-1]:
if dp[i-1][j-1]:
dp[i][j] = True
else:
dp[i][j] = False
elif p[i-1] == '?':
if dp[i-1][j-1]:
dp[i][j] = True
else:
dp[i][j] = False
elif p[i-1] == '*':
dp[i][j] = dp[i-1][j-1] or dp[i-1][j] or dp[i][j-1]
return dp[n][m]