多维动态规划题解——最长公共子序列【LeetCode】空间优化:两个数组(滚动数组)
1143. 最长公共子序列
基础解法请参考之前的一篇文章:
多维动态规划题解——最长公共子序列【LeetCode】记忆化搜索&&翻译成递推-CSDN博客
下面我们详细讲讲如何进行空间优化的,具体的优化技巧是什么
空间优化:两个数组(滚动数组)
class Solution:def longestCommonSubsequence(self, text1: str, text2: str) -> int:n, m = len(text1), len(text2)f = [[0]*(m+1) for _ in range(2)]for i,x in enumerate(text1):for j,y in enumerate(text2):# 之前1:1翻译为递推的代码如下,直接进行转换数组# if x==y:# f[i+1][j+1] = f[i][j]+1# else:# f[i+1][j+1] = max(f[i][j+1], f[i+1][j])if x==y:f[(i+1)%2][j+1] = f[i%2][j]+1else:f[(i+1)%2][j+1] = max(f[i%2][j+1], f[(i+1)%2][j])return f[n%2][m]
这段代码是对「最长公共子序列(LCS)」问题的 二维动态规划的空间优化版本,下面是其核心思路与技巧:
✅ 核心思想
🔁 空间优化
原始二维 DP 写法使用的是 f[i][j]
,即完整的 (n+1) x (m+1)
的矩阵。
由于每次只用到 上一行 和 当前行,所以我们可以把空间压缩为 2 行,交替使用:
f = [[0]*(m+1) for _ in range(2)]
🔄 滚动数组实现技巧
f[i % 2][j]
表示上一行的值,f[(i + 1) % 2][j]
表示当前行的值。
然后通过 % 2
控制行号交替使用:
if x == y:f[(i+1)%2][j+1] = f[i%2][j] + 1
else:f[(i+1)%2][j+1] = max(f[i%2][j+1], f[(i+1)%2][j])
✅ 返回值
return f[n % 2][m]
因为循环到 i=n-1
,最后一行是 f[n % 2]
,所以结果是 f[n % 2][m]
。
✅ 复杂度分析
项目 | 数值 |
时间复杂度 | O(n * m) |
空间复杂度 | O(2 * m) = O(m)(优化) |
✅ 总结一句话:
这段代码在不影响逻辑正确性的前提下,利用滚动数组把空间从 O(n×m) 降到了 O(m),是 LCS 问题中常用的 空间优化技巧。