给你一个字符串s和一个字符规律p,请你来实现一个支持'.'和'*'的正则表达式匹配
'.'匹配任意单个字符'*'匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串s的,而不是部分字符串示例1
输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串
示例2
输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次
示例3
输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')
提示
1 <= s.length <= 201 <= p.length <= 20s只包含从a-z的小写字母p只包含从a-z的小写字母,以及字符.和**时,前面都匹配到有效的字符题解
dp[i][j]表示s的前i个字符和p的前j个字符能否匹配dp[0][0]代表的是空字符的状态,因此dp[i][j]对应的字符s[i-1]和p[j-1]
p[j-1] != '*'时:
\(dp[i][j] =
\begin{cases}
dp[i-1][j-1], s[i]=p[j] \\
False, s[i] \neq p[j]
\end{cases}\)p[j-1] = '.'时: dp[i][j] = dp[i-1][j-1]p[j-1] == '*'时, 表示可对p[j]的前一个字符p[j−1]匹配(或理解为复制)任意次(包括0次)
dp[i][j] = dp[i][j-2]s[i]=p[j-1],则dp[i][j]可由dp[i-1][j-2]转移而来,此时有: dp[i][j] = dp[i-1][j-2] && s[i]=p[j-1]k次: 若s[i-k+1,...,i]=p[j-1],则有:dp[i][j] = dp[i-k][j-2] && s[i-k+1,...,i]=p[j-]dp[0][0]=Truedp[0][j]
p[j]='*'时,则有dp[0][j]=dp[0][j−2]s[0,...,j]无法与空字符匹配,因此有dp[0][j]=Falseclass Solution:
def isMatch(self, s: str, p: str) -> bool:
m, n = len(s) + 1, len(p) + 1
# 为便于状态更新,减少对边界的判断,初始二维dp数组维度为(m+1)×(n+1)
# 其中第一行和第一列的状态分别表示字符串s和p为空时的情况。
dp = [[False] * n for _ in range(m)]
dp[0][0] = True # 标识两个空字符串能够匹配
for j in range(1, n):
if p[j-1] == '*':
dp[0][j] = dp[0][j-2]
for i in range(1, m):
for j in range(1, n):
if s[i-1] == p[j-1] or p[j-1] == '.':
dp[i][j] = dp[i-1][j-1]
elif p[j-1] == '*': # 首字符不为*,则此处j>=2
dp[i][j] = dp[i][j-2] # *号复制前面字符零次
if s[i-1] == p[j-2] or p[j-2] == '.': # *号复制前面字符k(k>0)次
dp[i][j] |= dp[i-1][j]
return dp[-1][-1]