leetcode:1143. 最长公共子序列
dp[i][j] 二维数组的动态规划
状态转移方程是:
需要注意的是,dp数组是(m+1)*(n+1), 第一行和第一列的初始状态是为0的
n = len(text1)
m = len(text2)
(0,0)(0,1)(0,2)...(0,n)
(1,0)(1,1)(1,2)...
.
.
.
(m,0)
t1 = 0
if 第i个字符和第j个字符相等:
t1 = dp[i-1][j-1] + 1
t2 = max(dp[i-1][j], dp[i][j-1])
dp[i][j] = max(t1,t2)
以下是完整代码:
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
n = len(text1)
m = len(text2)
dp = [ [0]*(n+1) for _ in range(m+1)]
for i in range(1,m+1):
for j in range(1,n+1):
t1 = 0
if text2[i-1] == text1[j-1]:
t1 = dp[i-1][j-1] + 1
t2 = max(dp[i-1][j], dp[i][j-1])
dp[i][j] = max(t1,t2)
return dp[m][n]
dfs 加去重,属于动态规划的另外一种做法
重点是找到递归子结构(状态的转移),对于去重,使用的字典的结构(也可以使用二维数组来记录状态)
递归基的处理需要注意,我之前只考虑(0,1)(1,0)(0,0)的情况,然后没考虑(2,0)(3,0)等这种情况,导致撑爆了递归使用的栈,正确的做法是:
if i < 0 or j <0:
return 0
最后传入参数的时候,是len(text1)-1, len(text2)-1
,要减一
_dfs(len(text1)-1, len(text2)-1)
还有一个情况是,执行下一行时,报错res3
,没有定义
res =max(res1,res2,res3); dict1[(i,j)] = res
原来res是在if 判读语句中定义的,需要在外面初始化一下
以下是代码:
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
dict1 = {}
def _dfs(i,j):
if i < 0 or j <0:
return 0
# res1 = 0
# res2 = 0
if (i-1,j) in dict1.keys():
res1 = dict1[(i-1,j)]
else: res1 = _dfs(i-1,j); dict1[(i-1,j)] = res1
if (i,j-1) in dict1.keys():
res2 = dict1[(i,j-1)]
else: res2 = _dfs(i,j-1); dict1[(i,j-1)] = res2
res3 = 0
# print("i,j ",i, j)
if text1[i] == text2[j]:
if (i-1,j-1) in dict1.keys():
res3 = dict1[(i-1,j-1)]+1
else:
res32 = _dfs(i-1,j-1); dict1[(i-1,j-1)] = res32
res3 = res32 + 1 ;
res =max(res1,res2,res3); dict1[(i,j)] = res
return res
return _dfs(len(text1)-1, len(text2)-1)