动态规划四要素--通配符匹配
通配符匹配问题
给定一个字符串(s)和一个字符模式(p),实现一个支持’?‘和’*'的通配符匹配。
’ ? '可以匹配任何单个字符
’ * ’ 可以匹配任意字符串(包括空字符串)
两个字符串完全匹配才算匹配成功
最优解结构
dp[i][j] 表示s的前i个字符和p的前j个字符是否匹配
状态转移方程
- 如果s的第i个字符和p的第j个字符相同,或者p的第j个字符为 “?”:
dp[i][j] = dp[i-1][j-1]
- 如果p的第j个字符为 “?”,有两种情况:
1.这个**"?"**作为空字符串:
dp[i][j] = dp[i][j-1]
2.这个**"?"**作为任意字符串:
dp[i][j] = dp[i][j-1] or dp[i-1][j]
初始化dp
解决s的前0个字符和p的前i个字符能否匹配
dp[0][0] = True
dp[0][i] = dp[0][i-1] and p[i] == "*"
构造最优解
dp[m][n] 即为最优解
#m = len(s) ,n = len(p)
代码(python)
def isMatch(s, p):
m = len(s)
n = len(p)
dp = [[False for _ in range(n+1)] for _ in range(m+1)]
dp[m][n] = True
for i in range(m,-1,-1):
for j in range(n-1,-1,-1):
match = i<m and (s[i] == p[j] or p[j] == '.')
if j+1<n and p[j+1] == '*':
dp[i][j] = dp[i][j+2] or match and dp[i+1][j]
else:
dp[i][j] = match and dp[i+1][j+1]
return dp[0][0]
一个相似的问题–正则表达式匹配
问题
给定字符串s和字符串p,实现一个支持" . “和” * "的正则表达式匹配
" . " 匹配任意单个字符
" * " 匹配零个或多个前面的那个元素
最优解结构
dp[i][j] 表示s[i:] 和 p[j:] 匹配
状态转移方程
- 当 p[j] == s[i] 或 p[j] == " . " 时:
-
dp[i][j] = dp[i+1][j+1]
- 当 p[j] == " * " 时,有两种可能:
- 1 . 使前面那个字符消失:
-
dp[i][j-1] = dp[i][j+1]
- 2 . 复制前面那个字符,且当前面那个字符和s[i]一样时:
-
dp[i][j-1] = dp[i+1][j-1]
- 注意到我们实际上没有关注 dp[i][j] (当p[j] == " * "),因为这个值是没有意义的( " * " 单独没有任何意义)
初始化
m = len(s)
n = len (p)
dp = [[False for _ in range(n+1)] for _ in range(m+1)]
dp[m][n] = True
最优解
dp[0][0] 即为最优解
代码(python)
def isMatch(s,p):
m = len(s)
n = len(p)
dp = [[False for _ in range(n+1)] for _ in range(m+1)]
dp[m][n] = True
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
match = (i < m and (s[i] == p[j] or p[j] == '*'))
if j+1 < n and p[j+1] == '*':
dp[i][j] = dp[i][j+2] or dp[i+1][j] and match
else:
dp[i][j] = match and dp[i+1][j+1]
return dp[0][0]
难点
难点在于分析" * "时如何写转移状态方程使得可以一个个跳过特定字符最后达到末尾,相当于清空s中的相应某一字符,从而进入到同一个递归式。
状态结构的初始化也很需要思考。