115.不同的子序列
1、确定dp数组以及下标的含义
dpij:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dpij
2、确定递推公式
这一类问题,基本是要分析两种情况
- si - 1 与 tj - 1相等
- si - 1 与 tj - 1 不相等
(1)当si - 1 与 tj - 1相等时,dpij可以有两部分组成。
- 一部分是用si - 1来匹配,那么个数为dpi - 1j - 1。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dpi-1j-1。
- 一部分是不用si - 1来匹配,个数为dpi - 1j。
为什么还要考虑不用si - 1来匹配?例如: s:bagg 和 t:bag ,s3 和 t2是相同的,但是字符串s也可以不用s3来匹配,即用s0s1s2组成的bag。
当然也可以用s3来匹配,即:s0s1s3组成的bag。
所以当si - 1 与 tj - 1相等时,dpij = dpi - 1j - 1 + dpi - 1j;
(2)当si - 1 与 tj - 1不相等时,dpij只有一部分组成,
不用si - 1来匹配(就是模拟在s中删除这个元素),即:dpi - 1j。所以递推公式为:dpij = dpi - 1j;
3、dp数组如何初始化
dpi0 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。
那么dpi0一定都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1。
再来看dp0j,dp0j:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数。那么dp0j一定都是0,s如论如何也变成不了t。
最后就要看一个特殊位置了,即:dp00 应该是多少?dp00应该是1,空字符串s,可以删除0个元素,变成空字符串t。
4、确定遍历顺序
从上到下,从左到右
5、举例推导dp数组
python
class Solution:
def numDistinct(self, s: str, t: str) -> int:
dp = [[0] * (len(t) + 1) for _ in range(len(s) + 1)]
for i in range(len(s)+1):
dp[i][0] = 1
for i in range(1, len(s)+1):
for j in range(1, len(t)+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. 两个字符串的删除操作
1、确定dp数组以及下标的含义
dpij:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
2、确定递推公式
(1)当word1i - 1 与 word2j - 1相同的时候,dpij = dpi - 1j - 1;
(2)当word1i - 1 与 word2j - 1不相同的时候,有三种情况:
- 情况一:删word1i - 1,最少操作次数为dpi - 1j + 1
- 情况二:删word2j - 1,最少操作次数为dpij - 1 + 1
- 情况三:同时删word1i - 1和word2j - 1,操作的最少次数为dpi - 1j - 1 + 2
所以当word1i - 1 与 word2j - 1不相同的时候,递推公式:dpij = min({dpi - 1j - 1 + 2, dpi - 1j + 1, dpij - 1 + 1});
因为 dpij - 1 + 1 = dpi - 1j - 1 + 2,所以递推公式可简化为:dpij = min(dpi - 1j + 1, dpij - 1 + 1);
3、dp数组如何初始化
dpi0:word2为空字符串,以i-1为结尾的字符串word1要删除多少个元素,才能和word2相同呢,很明显dpi0 = i。
dp0j的话同理
4、确定遍历顺序
从上到下,从左到右
5、举例推导dp数组
python
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)]
for i in range(len(word1)+1):
dp[i][0] = i
for j in range(len(word2)+1):
dp[0][j] = j
for i in range(1, len(word1) + 1):
for j in range(1, len(word2) + 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)
return dp[-1][-1]
72. 编辑距离
1、确定dp数组以及下标的含义
dpij:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,将 word1 转换成 word2 所使用的最少操作数。
2、确定递推公式
(1)当word1i - 1 与 word2j - 1相同的时候,dpij = dpi - 1j - 1;
(2)当word1i - 1 与 word2j - 1不相同的时候,有三种情况:
- 情况一:删word1i - 1,最少操作次数为dpi - 1j + 1
- 情况二:删word2j - 1,最少操作次数为dpij - 1 + 1 (word2添加一个元素,相当于word1删除一个元素)
- 情况三:将word1i - 1替换为word2j - 1,操作的最少次数为dpi - 1j - 1 + 1
所以当word1i - 1 与 word2j - 1不相同的时候,递推公式:dpij = min({dpi - 1j - 1 + 1, dpi - 1j + 1, dpij - 1 + 1});
3、dp数组如何初始化
dpi0:word2为空字符串,以i-1为结尾的字符串word1要操作多少次,才能和word2相同呢,都删除,很明显dpi0 = i。
dp0j的话同理
4、确定遍历顺序
从上到下,从左到右
5、举例推导dp数组
python
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)]
for i in range(1, len(word1)+1):
dp[i][0] = i
for j in range(1, len(word2)+1):
dp[0][j] = j
for i in range(1, len(word1)+1):
for j in range(1, len(word2)+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]+1, dp[i-1][j]+1, dp[i][j-1]+1)
return dp[-1][-1]