Skip to main content

44.通配符匹配

标签: dynamic-programming, string

难度: Hard

通过率: 29.01%

原题链接: https://leetcode.com/problems/wildcard-matching/description/

题目描述

给定一个输入字符串(s)和一个模式(p),实现支持通配符的模式匹配,其中通配符支持:

  • '?' 匹配任何单个字符。
  • '*' 匹配任何字符序列(包括空序列)。

匹配应覆盖输入字符串的整个部分(不是部分匹配)。

解题思路

我们可以通过动态规划(Dynamic Programming)来解决这个问题。定义一个二维布尔数组 dp,其中 dp[i][j] 表示字符串 s 的前 i 个字符与模式 p 的前 j 个字符是否匹配。

动态规划方程:

  1. dp[0][0] = true:空字符串和空模式是匹配的。
  2. 如果 j > 0p[j-1] == '*'dp[0][j] = dp[0][j-1]:因为 * 可以匹配空字符串。
  3. 对于其他情况:
    • p[j-1] == '*' 时,dp[i][j] = dp[i-1][j] 或 dp[i][j-1]:前者表示 * 匹配一个字符,后者表示 * 匹配空字符串。
    • p[j-1] == '?'s[i-1] == p[j-1] 时,dp[i][j] = dp[i-1][j-1]:这表示如果匹配那么移除这两个字符后的结果应当是匹配的。

初始化:

  • dp[0][0] = true 表示两个空字符串是匹配的。
  • 对于 p 中以 * 开头的部分,初始化 dp[0][j] 为前一列的值,因为 * 可以匹配空字符串。

最终解:

  • dp[s.length][p.length] 表示字符串 s 和模式 p 是否整体匹配。

代码实现

def isMatch(s: str, p: str) -> bool:
# 获取字符串和模式的长度
m, n = len(s), len(p)
# 初始化动态规划表,dp[i][j] 表示 s 的前 i 个字符和 p 的前 j 个字符是否匹配
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]

# 通过动态规划填充表格
for i in range(1, m + 1):
for j in range(1, n + 1):
if p[j - 1] == '*':
# * 可以匹配空序列或者一个字符
dp[i][j] = dp[i][j - 1] or dp[i - 1][j]
elif p[j - 1] == '?' or s[i - 1] == p[j - 1]:
# ? 可以匹配任意单个字符
dp[i][j] = dp[i - 1][j - 1]

return dp[m][n]

复杂度分析

  • 时间复杂度: O(m×n)O(m \times n),其中 mm 是字符串 ss 的长度,nn 是模式 pp 的长度,因为我们需要填充大小为 (m+1)×(n+1)(m+1) \times (n+1) 的动态规划表。
  • 空间复杂度: O(m×n)O(m \times n),用于存储动态规划表。