最常见的子序列 - 优化内存

时间:2014-09-15 05:11:13

标签: algorithm optimization dynamic-programming

我有一个关于优化常见动态编程任务的内存的问题:找到两个字符串的最长公共子序列。我找到了一个response to a similar question,它有响应

  

请注意,当您计算表格中的下一行时   动态编程解决方案解决LCS问题,您只需要   上一行和当前行。然后你可以修改动态   编程解决方案只跟踪​​前一行和   当前行而不是m x n表。每次你到达终点   在当前行中,您将上一行设置为当前行,并且   再次从行的开头开始。你这样做m次m   是表中的行数。这将使用空间线性   列数。

但我有两个问题。

首先,当您使用将上一行设置为新行时,您是否仍然拥有旧行中的值?不会影响结果吗?

其次,为什么不能对列进行相同的优化呢?也就是说,当您到达列的末尾时,将前一列设置为当前列?

1 个答案:

答案 0 :(得分:2)

请查看有关此问题的wikipedia页面,尤其是包含表格的图表。要计算行i和列j中的单元格的结果,您需要在当前单元格的左侧,顶部和左上角的单元格的先前结果,因此LCS(i, j) = some_function(LCS(i-1, j), LCS(i, j-1), LCS(i-1, j-1)) 。要计算所有单元格的结果(您甚至需要做出最终答案),因此更容易计算沿行或列的条带中的所有中间结果。

回答你的问题:

  1. 可以安全地重复使用行i-2来存储行i的新结果,因为您只是从左到右覆盖旧结果。从当前行计算单元格i, j所需的唯一信息是单元格i, j-1,您刚刚使用上一步中的新值进行了更新。

  2. 您可以通过各种方式填充整个表格,最终获得右下角单元格的结果。您可以逐行(标准),逐列,交替一列,然后一行或沿对角线前面填充表格。试试自己的笔和纸:画一个网格并用十字架填充整个网格,但只标记已标记相关邻居的单元格。实现逐行或逐列版本更简单,因为您只需要2个固定长度的向量来保存中间结果。