我正在尝试解决 Cormem 的算法介绍第 3 版(第 405 页)中的动态编程问题,该问题提出以下问题:
回文是一些字母表上的非空字符串,向前和向后读取相同。回文的例子都是长度为 1 的字符串,,
civic
,racecar
, andaibohphobia
(fear of palindromes)。给出一个有效的算法来找到作为给定输入字符串的子序列的最长回文。例如,给定输入
character
,您的算法应该返回carac
。
好吧,我可以通过两种方式解决它:
第一个解决方案:
字符串的最长回文子序列 (LPS) 只是其自身的最长公共子序列及其反向。(我在解决了另一个要求序列的最长递增子序列的相关问题后构建了这个解决方案)。由于它只是一个 LCS 变体,它还需要 O(n²) 时间和 O(n²) 内存。
第二种解决方案:
第二种解决方案更详细一些,但也遵循通用 LCS 模板。它来自以下重复:
lps(s[i..j]) =
s[i] + lps(s[i+1]..[j-1]) + s[j], if s[i] == s[j];
max(lps(s[i+1..j]), lps(s[i..j-1])) otherwise
计算 lps 长度的伪代码如下:
compute-lps(s, n):
// palindromes with length 1
for i = 1 to n:
c[i, i] = 1
// palindromes with length up to 2
for i = 1 to n-1:
c[i, i+1] = (s[i] == s[i+1]) ? 2 : 1
// palindromes with length up to j+1
for j = 2 to n-1:
for i = 1 to n-i:
if s[i] == s[i+j]:
c[i, i+j] = 2 + c[i+1, i+j-1]
else:
c[i, i+j] = max( c[i+1, i+j] , c[i, i+j-1] )
如果我想有效地构造lps,它仍然需要 O(n²) 时间和内存(因为我需要桌子上的所有单元格)。分析相关问题,例如 LIS,可以用 LCS 以外的方法解决,用更少的内存(LIS 可以用 O(n) 内存解决),我想知道是否可以用 O(n) 内存解决它,也。
LIS 通过链接候选子序列来实现这个界限,但是对于回文则更难,因为这里重要的不是子序列中的前一个元素,而是第一个元素。有谁知道是否可以做到,或者以前的解决方案内存是最优的吗?