动态规划:保存之前的计算结果以避免重复计算
- 自下而上:先解决子问题,逐步填表(Tabulation)
- 自上而下:不断分解问题直到最小,记忆存储(Memorization)
题目要求
给定字符串 s
和字符规律 p
,判断s
能否由p
匹配。
p[0 : j]
能否匹配 s[0 : i]
与其子问题(如 p[0 : j - 1]
能否匹配 s[0 : i]
)的解有关,考虑用自下而上填表方式。
令dp[i][j]
表示 s[0 : i]
能否由匹配 p[0 : j]
,这里由于*
的存在可以有空字符,所以令dp[i + 1][j + 1]
表示 s[0 : i]
能否由匹配 p[0 : j]
,用dp[0][:]
表示s
前空字符的匹配,然后分析与子问题的解的关系…
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if s is None or p is None:
return False
# 初始化全为否
dp = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
# 空字符可以匹配
dp[0][0] = True
# 初始化空字符是否可匹配
for i in range(2, len(p) + 1):
if p[i - 1] == '*':
dp[0][i] = dp[0][i - 2]
# 逐步填表解决子问题,最后得到解
for i in range(1, len(s) + 1):
for j in range(1, len(p) + 1):
if s[i - 1] == p[j - 1] or p[j - 1] == '.':
dp[i][j] = dp[i - 1][j - 1]
elif p[j - 1] == '*':
if p[j - 2] != s[i - 1] and p[j - 2] != '.':
dp[i][j] = dp[i][j - 2]
else:
dp[i][j] = dp[i - 1][j] or dp[i][j - 1] or dp[i][j - 2]
return dp[len(s)][len(p)]