最长回文子序列的长度问题(状态压缩优化版本)
字数 2340 2025-12-04 04:27:27
最长回文子序列的长度问题(状态压缩优化版本)
题目描述
给定一个字符串 s,求其最长回文子序列(Longest Palindromic Subsequence, LPS)的长度。回文子序列是通过删除原字符串中的某些字符(也可以不删除)而不改变剩余字符的相对顺序得到的一个序列,且该序列正读反读相同。例如,字符串 "bbbab" 的最长回文子序列是 "bbbb",长度为 4。要求使用动态规划求解,并进一步优化空间复杂度至 O(n)。
解题思路
-
基本区间DP定义
- 定义
dp[i][j]表示字符串s[i..j]的最长回文子序列长度。 - 初始条件:当
i == j时,dp[i][j] = 1(单个字符本身就是回文)。 - 状态转移方程:
- 若
s[i] == s[j],则dp[i][j] = dp[i+1][j-1] + 2。 - 若
s[i] != s[j],则dp[i][j] = max(dp[i+1][j], dp[i][j-1])。
- 若
- 最终答案:
dp[0][n-1]。
- 定义
-
空间优化挑战
- 基本DP需要 O(n²) 空间,但观察状态转移发现:计算
dp[i][j]时仅依赖下一行(i+1)和同一行左侧(j-1)的值。 - 优化思路:使用一维数组
dp[j]代替二维数组,按行从下往上、每行从左往右更新。
- 基本DP需要 O(n²) 空间,但观察状态转移发现:计算
逐步推导
步骤1:基本DP填表示例(以 s = "bbbab" 为例)
- 初始化:所有
i == j的格子为 1。 - 填表顺序:按区间长度
L从 2 到 n 遍历。
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
| 0 b | 1 | 2 | 2 | 3 | 4 |
| 1 b | - | 1 | 2 | 2 | 3 |
| 2 b | - | - | 1 | 1 | 3 |
| 3 a | - | - | - | 1 | 1 |
| 4 b | - | - | - | - | 1 |
步骤2:空间优化策略
- 使用一维数组
dp表示当前行(第i行)的结果。 - 额外变量
prev保存dp[i+1][j-1]的值(即上一轮计算中dp[j-1]的旧值)。 - 更新顺序:
- 外层循环
i从n-1到0倒序(从最后一行往上)。 - 内层循环
j从i+1到n-1正序。 - 在更新
dp[j]前,用temp保存当前dp[j](即下一行的dp[j]),用于后续计算prev。
- 外层循环
步骤3:优化后的状态转移
- 若
s[i] == s[j]:- 如果
j == i+1,直接赋值为 2(相邻字符相同)。 - 否则,
dp[j] = prev + 2(prev即dp[i+1][j-1]的旧值)。
- 如果
- 若
s[i] != s[j]:dp[j] = max(dp[j], dp[j-1])(dp[j]是下一行的值,dp[j-1]是当前行已更新的值)。 - 每轮内层循环结束时,更新
prev = temp(为下一轮j+1准备)。
步骤4:示例演示(s = "bbbab")
初始:dp = [1,1,1,1,1](对应 i=n-1 时的初始值)。
-
i=3(字符
a):- j=4:
s[3]!=s[4],dp[4]=max(dp[4],dp[3])=max(1,1)=1。 - 更新后
dp=[1,1,1,1,1]。
- j=4:
-
i=2(字符
b):- j=3:
s[2]!=s[3],dp[3]=max(1,1)=1。 - j=4:
s[2]==s[4],prev=dp[3]的旧值=1,dp[4]=prev+2=3。 - 更新后
dp=[1,1,1,1,3]。
- j=3:
-
i=1(字符
b):- j=2:
s[1]==s[2],prev=dp[1]的旧值=1,dp[2]=1+2=3?- 纠正:
j=2时,j-i=1,直接赋 2(相邻相同字符)。
- 纠正:
- j=3:
s[1]!=s[3],dp[3]=max(dp[3],dp[2])=max(1,2)=2。 - j=4:
s[1]==s[4],prev=dp[3]的旧值=1,dp[4]=1+2=3?- 纠正:
prev应为i=1,j=4时dp[3]在下一行(i=2)的值,即 1,正确。
- 纠正:
- 更新后
dp=[1,1,2,2,3]。
- j=2:
-
i=0(字符
b):- j=1:相邻相同,
dp[1]=2。 - j=2:
s[0]==s[2],prev=dp[1]的旧值=1,dp[2]=1+2=3?- 纠正:
j=2时,prev取下一行dp[1]的旧值(即 i=1 时dp[1]=1),正确。
- 纠正:
- j=3:
s[0]!=s[3],dp[3]=max(2,3)=3。 - j=4:
s[0]==s[4],prev=dp[3]的旧值=2,dp[4]=2+2=4。 - 最终
dp[4]=4。
- j=1:相邻相同,
复杂度分析
- 时间复杂度:O(n²)。
- 空间复杂度:O(n)。
关键点
- 优化时需注意
prev的保存时机,确保它代表dp[i+1][j-1]。 - 相邻字符(
j=i+1)需单独处理。
此方法将经典区间DP的空间消耗降低,适用于大规模字符串处理。