[1143][中等][动态规划] 最长公共子序列
题目描述
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
示例 1:
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace",它的长度为 3。
示例 2:
输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc",它的长度为 3。
示例 3:
输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0。
提示:
1 <= text1.length <= 1000
1 <= text2.length <= 1000
输入的字符串只含有小写英文字符。
解题思路
空间优化点
使用滚动数组的思想对使用的空间进行优化, 原本二维的状态转移表的空间复杂度为, 其中和分别是两个字符串的长度. 观察状态转移方程, 对于, 使用到的所有依赖为, , . 所以我们仅存储:
上一列的结果
这样, 从前到后(状态表从上到下)循环时, 在计算, 已经计算得到了, 覆盖了. 这样我们就能计算得到, 用来覆盖, 从而在列的维度上逐步推进.
需要注意覆盖了的值, 而在计算又需要的值, 因此需要一个额外的标量变量来存储左上角(即)的值.
代码如下:
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
n, m = len(text1), len(text2)
cache = [0] * n
for i in range(m):
for j in range(n):
if j == 0:
cache[j] = 1 if text1[j] == text2[i] else cache[j]
la = cache[j] # 为下一轮备用, 记录左上角的值
else:
tla = cache[j]
cache[j] = la + 1 if text1[j] == text2[i] else max(cache[j], cache[j - 1])
la = tla # 为下一轮备用, 记录左上角的值
return cache[-1]
相关题目
[718][中等][动态规划][滑动窗口] 最长重复子数组
最后更新于
这有帮助吗?