115. 不同的子序列
找到s中包含t的所有子序列的个数,t是模式(如果找连续的t用kmp)
思路:
思路:还是使用二维的dp, dp[i][j]表示 s[0..i-1]中包含 t[0..j-1]子序列的最大数量
初始化:dp[i][0] = 1 ; dp[0][j] = 0 注意dp[0][0]=1
递推:
eg: s=bagg t=bag dp[4][3]
1: s[i-1]==t[j-1] bag[g] ,直接使用dp[i-1][j-1]的子序列数量,还需要加上删除s[i-1]的情况,也就是dp[i-1][j]
2: s[i-1]==t[j-1] 那就删除s的末尾字符的数量dp[i-1][j]
class Solution:
def numDistinct(self, s: str, t: str) -> int:
m, n = len(s), len(t)
# 初始化
dp = [[0] * (n+1) for _ in range(m+1)]
for i in range(m+1):
dp[i][0] = 1 # 始终含空串
for j in range(1, n+1): # # !千万不能把dp[0][0]=1改成0
dp[0][j] = 0
for i in range(1, m+1):
for j in range(1, n+1): # 注意1开始
if s[i-1] == t[j-1]:
dp[i][j] = dp[i-1][j-1] + dp[i-1][j] # 相同时s和t都删除当前/ dp[i-1][j] 删除s的s[i-1]
else:
dp[i][j] = dp[i-1][j] # 为什么只有i-1? 因为从s中找t,s长啊
return dp[-1][-1]
注意初始化dp[0][0]=1!
583. 两个字符串的删除操作
这道题更进一步,s和t两边都可以删除了。
思路:
思路:
定义:dp[i][j]表示s[0..i-1]和t[0..j-1]两个子串要达到相等,需要删除的最少次数
初始化:dp[i][0]=i dp[0][j]=j 任意一边为空,另一边需要删除所有的字符
递推:
s[i-1]==t[j-1]: 相同就不需要删除了,看dp[i-1][j-1]的最小删除数量
s[i-1]!=t[j-1]: 三种情况,删除s、删除t、删除st的末尾,前面两个操作步骤+1,后面两个+2,取最小
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0] * (n+1) for _ in range(m+1)]
# 初始化一定要小心 dp[0][0]=0
for i in range(m+1):
dp[i][0] = i
for j in range(n+1):
dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+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] + 2,
min(
dp[i-1][j] + 1,
dp[i][j-1] + 1
)
)
return dp[m][n]
72. 编辑距离
思路:
1 定义:dp[i][j]表示word[0,...,i-1]前i个字符和word2[0,...,j-1]前j个子串的最小编辑距离
2 初始化:dp[i][0] dp[0][j] 任意一边空,另一边需要删除所有字符
3 递推:
s[i-1]==t[j-1]时候,直接取dp[i-1][j-1]不需要编辑了,跳过。
如果不相同,考虑对s插入(dp[i][j-1] 左)、删除(dp[i-1][j]上)、替换(dp[i-1][j-1]) 操作+1
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0] * (n+1) for _ in range(m+1)]
for i in range(m+1):
dp[i][0] = i
for j in range(n+1):
dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+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, # 替换
min(
dp[i][j-1] + 1, # 插入
dp[i-1][j] + 1 # 删除
)
)
return dp[m][n]
检查第四天!orz有点累了,编辑距离这类代码看似简单,好容易搞混啊。