字符串匹配
通配符匹配
给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
示例1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例2:
输入:
s = "aa"
p = "*"
输出: true
解释: '*' 可以匹配任意字符串。
方案 动态规划
思路: 在给定的模式p
中,只会有三种类型的字符出现:
- 小写字母
a-z
,可以匹配对应的一个小写字母; - 问号
?
,可以匹配任意一个小写字母; - 星号
∗
,可以匹配任意字符串,可以为空,也就是匹配零或任意多个小写字母。
其中,小写字母和问号的匹配是确定的,而*号的匹配是不确定的,因此我们需要枚举所有的匹配情况。为了减少重复枚举,我们可以使用动态规划来解决本题。
-
状态定义:
dp[i][j]
表示字符串s
的前i
个字符和模式p
的前j
个字符是否能匹配。 -
状态转移方程:
- 如果
p[j]
==s[i]
时,方程为:dp[i][j]=dp[i-1][j-1]
- 如果
p[j]
为?
时,那么对s[i]
没有任何要求,方程为:dp[i][j]=dp[i-1][j-1]
- 如果
p[j]
为*
号时,同样对s[i]
没有任何要求, 但是*
号可以匹配0
或任意多个小写字母
,因此方程为:dp[i][j]=dp[i][j-1]||dp[i-1][j]
- 如果
-
初始化状态:
- dp 初始都为 false
- dp[0][0]=true,即当字符串
s
和模式p
均为空时,匹配成功 - dp[i][0]=false,即空模式无法匹配非空字符串
- dp[0][j] 时:
- 如果
p[j-1]=='*'
,则有 dp[0][j]=true;
- 如果
-
问题答案: dp[row][col] 为最终答案
:::details 点击查看代码
function isMatch(s, p) {
const row=s.length;
const col=p.length;
const dp=new Array(row+1).fill(0).map(()=>new Array(col+1).fill(false));
dp[0][0]=true;
for(let i=1;i<=col;i++){
if(p[i-1]=='*'){
dp[0][i]=true;
}else{
break;
}
}
for(let i=1;i<=row;i++){
for(let j=1;j<=col;j++){
if(p[j-1]=='*'){
dp[i][j]=dp[i][j-1]||dp[i-1][j];
}else if(p[j-1]=='?'||s[i-1]==p[j-1]){
dp[i][j]=dp[i-1][j-1];
}
}
}
return dp[row][col];
};
:::
性能分析:
- 时间复杂度:O(mn)
- 空间复杂度:O(mn)