一、115. 不同的子序列
题目链接:115. 不同的子序列 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——115. 不同的子序列
视频讲解:动态规划之子序列,为了编辑距离做铺垫 | LeetCode:115.不同的子序列_哔哩哔哩_bilibili
动态规划五部曲:
1. 确定 dp 数组及下标含义:dp[ i ][ j ] 表示以 i - 1 结尾的 s 中有以 j - 1 为结尾的 t 的个数。输出dp[-1][-1]
2. 确定递推公式:
if s[ i - 1 ] == t[ j - 1 ]:
dp[ i ][ j ] = dp[ i - 1 ][ j - 1 ](使用s[ i - 1 ]) + dp[ i - 1 ][ j ](不使用 s[ i - 1 ] 的情况,模拟删除的情况)
else:
dp[ i ][ j ] = dp[ i - 1 ][ j ]
3. 确定dp数组如何初始化:dp[ i ][ 0 ] = 1, dp[ 0 ][ j ] = 0, dp[ 0 ][ 0 ] = 1
4. 确定遍历顺序:for i in range(1, len(s)): for j in range(1, len(t)):
5. 举例推导dp数组。
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)):
dp[i][0] = 1
dp[0][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. 两个字符串的删除操作
题目链接:583. 两个字符串的删除操作 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——583. 两个字符串的删除操作
视频讲解:动态规划之子序列,为了编辑距离做铺垫 | LeetCode:115.不同的子序列_哔哩哔哩_bilibili
自己思路:求最大公共子序列,两个单词字母数字之和 - 2*最大公共子序列
动态规划五部曲:
1. 确定 dp 数组及下标含义:dp[ i ][ j ] 表示以 i - 1 为结尾的 word1 和 以 j - 1 为结尾的 word2 为相同最小操作次数
2. 确定递推公式:
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(删除元素 i - 1), dp[ i ][ j - 1 ](删除元素 j - 1), dp[ i - 1][ j - 1 ] + 2(两个元素都删)),要求最少,所以用min
3. 确定dp数组如何初始化:dp[ 0 ][ j ] = j,如果word1为空,word2要删除 j 个元素才为空;
dp[ i ][ 0 ] = i,如果word2为空,word1要删除 i 个元素才为空
4. 确定遍历顺序:
for i in range(1, len(word1) + 1):
for j in range(1, len(word2) + 1):
5. 举例推导dp数组。
"""
最大公共子序列解决
"""
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):
for j in range(1, len(word2) + 1):
if word1[i - 1] == word2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
result = len(word1) + len(word2) - 2 * dp[-1][-1]
return result
"""
Carl方法
"""
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
# 创建dp数组
dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)]
# 初始化
for i in range(len(word1)):
dp[i][0] = i
for j in range(len(word2)):
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, dp[i - 1][j - 1] + 2)
return dp[-1][-1]
三、72. 编辑距离
题目链接:72. 编辑距离 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——72. 编辑距离
视频讲解:动态规划终极绝杀! LeetCode:72.编辑距离_哔哩哔哩_bilibili
动态规划五部曲:
1. 确定 dp 数组及下标含义:dp[ i ][ j ] 表示以 i - 1 为结尾的 word1 和 以 j - 1 为结尾的 word2,最少的操作次数
2. 确定递推公式:
if word1[ i - 1 ] == word2[ j - 1 ]:
dp[ i ][ j ] = dp[ i -1 ][ j - 1 ]
else:
# 增,dp[ i - 1 ][ j ]+1,对 word2 进行删除操作,相当于对 word1 进行增加的逆向操作
# 删,dp[ i ][ j - 1 ]+1,删除word1中元素
# 改,dp[ i - 1 ][ j - 1 ]+1,不相同替换操作加一
dp[ i ][ j ] = min(dp[ i - 1 ][ j ]+1, dp[ i ][ j - 1 ]+1, dp[ i - 1 ][ j - 1 ]+1)
3. 确定dp数组如何初始化:dp[i][0] = i, dp[0][j] = j
4. 确定遍历顺序:
for i in range(1, len(word1) + 1):
for j in range(1, len(word2) + 1):
5. 举例推导dp数组。
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
# 创建dp数组
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, dp[i - 1][j - 1] + 1)
return dp[-1][-1]
四、编辑距离总结篇
文章讲解:代码随想录 (programmercarl.com)——编辑距离总结篇