给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘’ 的通配符匹配。’?’ 可以匹配任何单个字符。’’ 可以匹配任意字符串(包括空字符串)。两个字符串完全匹配才算匹配成功。说明: s 可能为空,且只包含从 a-z 的小写字母。p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
力扣(LeetCode)第44题
确定状态
动态规划一般来讲,目标是求什么则什么即为状态,然后分析当前状态和之前状态的推导关系,进而进行穷举所有状态即可。
本题中用 dp[i][j] 表示 s 以 i 位置结尾和 p 以 j 位置结尾时的匹配情况。
状态转移方程
根据题目要求,p 中字符有三种匹配情况:
①.p[j] == ‘?’
‘?’ 可以匹配任意单个字符,此时 dp[i][j] = dp[i-1][j-1]。
②.p[j] == ‘a-z’
此时若 s[i-1] = p[j-1],则 dp[i][j] = dp[i-1][j-1]。
③.p[j] == *
因为 * 可以匹配任意数量的任意字符,则有两种情况:
* 匹配 0 个字符,则 dp[i][j] = dp[i][j-1];
* 匹配 多个字符,则 dp[i][j] = dp[i-1][j];
边界及状态初始化
- 增加相同开头字符
为方便处理边界情况,使字符串下标 1 开始遍历,在 s 和 q 开头均增加相同字符 ‘a’ ,此时 dp[0][0] = 1。 - 边界条件
在上述的状态转移方程中,由于 dp[i][j] 对应着 s 的前 i 个字符和 p 的前 j 个字符,因此所有的所有的 dp[0][j]、dp[i][0] 都是边界条件。
因为 p[0] 不为 ‘’,所以 dp[i][0] 始终为不匹配;
只有当 p[j] =’’ 时,dp[0][j] = dp[0][j-1]。
确认结果
s 和 p 最末位置的匹配结果就是本题的结果,即 dp[s.size()-1][p.size()-1]。
代码示例
class Solution {
public:
bool isMatch(string s, string p) {
s= 'a'+s;
p= 'a'+p;
vector<vector<int>> dp(s.size(),vector(p.size(),0));//dp[i][j] 表示以i、j结尾的匹配情况
dp[0][0] = 1;
for(int j = 1;j < p.size();j++)
{
if( p[j] == '*')
{
dp[0][j] = dp[0][j-1];
}
}
for(int i = 1;i < s.size();i++)
{
dp[i][0] = 0;
}
for(int i = 1;i < s.size();i++)
{
for( int j = 1;j < p.size();j++)
{
if( p[j] == '?')
{
dp[i][j] = dp[i-1][j-1];
}
else if( p[j] == '*')
{
dp[i][j] = dp[i][j-1] || dp[i-1][j];
}
else
{
if( s[i] == p[j] )
{
dp[i][j] = dp[i-1][j-1];
}
}
}
}
return dp[s.size()-1][p.size()-1];
}
};