动态规划解决通配符匹配问题

通配符匹配问题

给定一个字符串(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中的相应某一字符,从而进入到同一个递归式。
状态结构的初始化也很需要思考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通配符匹配问题可以使用动态规划解决。具体的实现如下: ```python def is_match(s, p): m, n = len(s), len(p) # 创建一个二维数组 dp,用于记录匹配状态 dp = [[False] * (n+1) for _ in range(m+1)] dp[0][0] = True # 处理模式串 p 以连续的 '*' 开头的情况 for j in range(1, n+1): if p[j-1] == '*': dp[0][j] = dp[0][j-1] # 动态规划遍历字符串 s 和模式串 p for i in range(1, m+1): for j in range(1, n+1): if p[j-1] == '?' or s[i-1] == p[j-1]: dp[i][j] = dp[i-1][j-1] elif p[j-1] == '*': dp[i][j] = dp[i][j-1] or dp[i-1][j] return dp[m][n] ``` 这里使用一个二维数组 `dp` 来记录匹配状态。`dp[i][j]` 表示字符串 `s` 的前 `i` 个字符和模式串 `p` 的前 `j` 个字符是否匹配。初始时,将 `dp[0][0]` 设置为 `True`,表示两个空串是匹配的。然后处理模式串 `p` 以连续的 '*' 开头的情况,如果遇到 '*',则将 `dp[0][j]` 设置为 `dp[0][j-1]`。 接下来,使用动态规划遍历字符串 `s` 和模式串 `p`。如果当前字符匹配或者模式串中为 '?' 通配符,则将当前匹配状态设为上一个匹配状态 `dp[i-1][j-1]`。如果当前字符为 '*' 通配符,则可以选择忽略该字符(`dp[i][j-1]`)或者将该字符匹配多个前面的字符(`dp[i-1][j]`)。最终返回 `dp[m][n]`,其中 `m` 和 `n` 分别为字符串 `s` 和模式串 `p` 的长度。 你可以调用 `is_match` 函数并传入两个字符串来测试它的功能。例如: ```python s = "acdcb" p = "a*c?b" result = is_match(s, p) print(result) # 输出:True ``` 这里的字符串 `s` 匹配模式串 `p`,返回结果为 `True`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值