代码随想录算法训练营第五十天| 动态规划12
115. 不同的子序列
但相对于刚讲过 392.判断子序列,本题 就有难度了 ,感受一下本题和 392.判断子序列 的区别。代码随想录
dp[i][j]表示以s[i-1]结尾的子序列中,出现以t[j-1]结尾的t的个数
注意初始化时,dp[0][0]的值不要重复初始化,应该为1,空字符串s删除0个元素可以变成空字符串t
class Solution:
def numDistinct(self, s: str, t: str) -> int:
n1=len(s)
n2=len(t)
dp=[[0]*(n2+1) for _ in range(n1+1)]
for i in range(n1):
dp[i][0]=1
for j in range(1,n2):
dp[0][j]=0
for i in range(1,n1+1):
for j in range(1,n2+1):
if s[i-1]==t[j-1]:
dp[i][j]=dp[i-1][j-1]+dp[i-1][j]
else:
dp[i][j]=dp[i-1][j]
return dp[-1][-1]
583. 两个字符串的删除操作
本题和动态规划:115.不同的子序列 相比,其实就是两个字符串都可以删除了,情况虽说复杂一些,但整体思路是不变的。代码随想录
参照115的思路推导,
1. 注意初始化边界值,需到n1+1和n2+1才能完全覆盖
2. word1[i-1]不等于word2[j-1]时,存在三种情况,
情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
n1=len(word1)
n2=len(word2)
dp=[[0]*(n2+1) for _ in range(n1+1)]
for i in range(n1+1):
dp[i][0]=i
for j in range(n2+1):
dp[0][j]=j
for i in range(1,n1+1):
for j in range(1,n2+1):
if word1[i-1]==word2[j-1]:
dp[i][j]=dp[i-1][j-1]
else:
dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+2)
return dp[-1][-1]
72. 编辑距离
最终我们迎来了编辑距离这道题目,之前安排题目都是为了 编辑距离做铺垫。代码随想录
如果word1[i - 1]等于word2[j - 1] 那么说明不用任何编辑,dp[i][j] 就应该是 dp[i - 1][j - 1],即dp[i][j] = dp[i - 1][j - 1];
如果不相等,此时需要编辑:
1. word1删除一个元素,即 dp[i][j] = dp[i - 1][j] + 1;
2. word1添加一个元素和word2删除一个元素的操作数一样,即 dp[i][j] = dp[i][j - 1] + 1;
3. word1替换一个元素,word1替换word1[i-1]使其与word2[j-1]相同,即p[i][j] = dp[i - 1][j - 1] + 1;
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
n1=len(word1)
n2=len(word2)
dp=[[0]*(n2+1) for _ in range(n1+1)]
for i in range(n1+1):
dp[i][0]=i
for j in range(n2+1):
dp[0][j]=j
for i in range(1,n1+1):
for j in range(1,n2+1):
if word1[i-1]==word2[j-1]:
dp[i][j]=dp[i-1][j-1]
else:
dp[i][j]=min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+1
return dp[-1][-1]