最长公共子序列 编辑距离【基础算法精讲 19】_哔哩哔哩_bilibili
1143. 最长公共子序列
给定两个字符串 text1
和 text2
,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0
。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
- 例如,
"ace"
是"abcde"
的子序列,但"aec"
不是"abcde"
的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
一 · 递归搜索 + 保存计算结果 = 记忆化搜索
class Solution:
def longestCommonSubsequence(self, s: str, t: str) -> int:
n, m = len(s), len(t)
@cache
def dfs(i, j):
if i < 0 or j < 0:
return 0
if s[i] == t[j]:
return dfs(i - 1, j - 1) + 1
return max(dfs(i - 1, j), dfs(i, j - 1))
return dfs(n - 1, m - 1)
二 · 1:1 翻译成递推
class Solution:
def longestCommonSubsequence(self, s: str, t: str) -> int:
n, m = len(s), len(t)
f = [[0] * (m + 1) for _ in range(n + 1)]
for i, x in enumerate(s):
for j, y in enumerate(t):
f[i + 1][j + 1] = f[i][j] + 1 if x == y else \
max(f[i][j + 1], f[i + 1][j])
return f[n][m]
三 · 空间优化:两个数组(滚动数组)
class Solution:
def longestCommonSubsequence(self, s: str, t: str) -> int:
n, m = len(s), len(t)
f = [[0] * (m + 1) for _ in range(2)]
for i, x in enumerate(s):
for j, y in enumerate(t):
f[(i + 1) % 2][j + 1] = f[i % 2][j] + 1 if x == y else \
max(f[i % 2][j + 1], f[(i + 1) % 2][j])
return f[n % 2][m]
四 · 空间优化:一个数组
class Solution:
def longestCommonSubsequence(self, s: str, t: str) -> int:
f = [0] * (len(t) + 1)
for x in s:
pre = 0 # f[0]
for j, y in enumerate(t):
tmp = f[j + 1]
f[j + 1] = pre + 1 if x == y else max(f[j + 1], f[j])
pre = tmp
return f[-1]
72. 编辑距离
给你两个单词 word1
和 word2
, 请返回将 word1
转换成 word2
所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
一 · 递归搜索 + 保存计算结果 = 记忆化搜索
class Solution:
def minDistance(self, s: str, t: str) -> int:
n, m = len(s), len(t)
@cache
def dfs(i, j):
if i < 0: return j + 1
if j < 0: return i + 1
if s[i] == t[j]: return dfs(i - 1, j - 1)
return min(dfs(i - 1, j), dfs(i, j - 1), dfs(i - 1, j - 1)) + 1
return dfs(n - 1, m - 1)
二 · 1:1 翻译成递推
class Solution:
def minDistance(self, s: str, t: str) -> int:
n, m = len(s), len(t)
f = [[0] * (m + 1) for _ in range(n + 1)]
f[0] = list(range(m + 1))
for i, x in enumerate(s):
f[i + 1][0] = i + 1
for j, y in enumerate(t):
f[i + 1][j + 1] = f[i][j] if x == y else \
min(f[i][j + 1], f[i + 1][j], f[i][j]) + 1
return f[n][m]
三 · 空间优化:两个数组(滚动数组)
class Solution:
def minDistance(self, s: str, t: str) -> int:
n, m = len(s), len(t)
f = [list(range(m + 1)), [0] * (m + 1)]
for i, x in enumerate(s):
f[(i + 1) % 2][0] = i + 1
for j, y in enumerate(t):
f[(i + 1) % 2][j + 1] = f[i % 2][j] if x == y else \
min(f[i % 2][j + 1], f[(i + 1) % 2][j], f[i % 2][j]) + 1
return f[n % 2][m]
四 · 空间优化:一个数组
class Solution:
def minDistance(self, s: str, t: str) -> int:
f = list(range(len(t) + 1))
for x in s:
pre = f[0]
f[0] += 1
for j, y in enumerate(t):
tmp = f[j + 1]
f[j + 1] = pre if x == y else min(f[j + 1], f[j], pre) + 1
pre = tmp
return f[-1]