刷力扣学习记忆化递归[leetcode10. 正则表达式匹配]
原题链接
https://leetcode-cn.com/problems/regular-expression-matching/
当你发现你的递归里有很多重复的函数调用的时候,就要想想使用记忆化递归了,使用起来就是在本来要return
的时候先把他储存起来,然后再返回
同时,调用函数的时候多了几步,即,如果已经储存过,直接返回,如果没有储存过,则储存了再返回
题解
memo = [[None]*N for _ in range(M+1)] #用于储存
M,N = len(s),len(p)
def dfs (i,j):
if j >= N:
return i >= M
if memo[i][j] != None:
return memo[i][j]
matchable = i < len(s) and p[j] in {s[i], '.'}
if p[j+1] == '*' and j+1<N:
if matchable:
memo[i][j] = dfs(i+1,j) or dfs(i,j+2)
else:
memo[i][j] = dfs(i,j+2)
else:
memo[i][j] = matchable and dfs(i+1,j+1)
return memo[i][j]
dfs(0,0)
这是一道困难题,我感觉主要的难点在于讨论应该结束的条件,题目中有两条字符串,做这种题时应该确定一条作为主字符串,谈论返回就只讨论它,这样思考起来就会简单很多。
除了使用记忆化递归,这题还可以使用DP来做,似乎其他人都是这么做的。。我也写一个DP的解法,其实递归与DP的思路非常相像,但DP还不用考虑这么多结束条件,暴力枚举就行了。
题解II
def isMatch(self, s: str, p: str) -> bool:
M,N = len(s),len(p)
def match (i,j):
return i>=0 and bool(p[j] in {s[i],'.'})
dp = [[False]*(N+1) for _ in range(M+1)] #多加一行一列来匹配空的情况
dp[0][0] = True
for i in range(M+1): #空与a*匹配的特殊情况
for j in range(1,N+1):
if p[j-1] == '*':
dp[i][j] |= dp[i][j-2] or (match(i-1,j-2) and dp[i-1][j])
else:
dp[i][j] |= match(i-1,j-1) and dp[i-1][j-1]
return dp[M][N]