arrays - ocaml lcs 没有像数组这样的对象

标签 arrays ocaml fold lcs

如何在 ocaml 中不使用数组而仅使用列表折叠来找到最长公共(public)子序列

最佳答案

这是 Dynamic programming 的经典示例: 这 要实现的函数可以轻松地递归指定,但是 递归调用对应的子问题有很多 重叠。一个简单的递归实现会做无用的工作 重新计算这些子问题,导致运行时间呈指数增长, 而内存或不同的方法都会导致多项式 算法。

给定最长公共(public)子序列(LCS)问题的公式 on Wikipedia 如下(伪代码):

LCS(X,Y,0,0) = []
LCS(X,Y,i,j) =
  if X[i] = Y[j] then X[i]::LCS(X,Y,i-1,j-1)
  else longest(LCS(X,Y,i-1,j), LCS(X,Y,i,j-1))

当转换为列表而不是数组和索引时 参数,您有以下公式(仍然是伪代码):

LCS([], []) = []
LCS([x],[]) = []
LCS([], [y]) = []
LCS(x::xs, y::ys) =
  if x = y then x::LCS(xs, ys)
  else longest(LCS(x::xs, ys), LCS(xs, y::ys))

从中获得 OCaml 实现应该很容易(我假设 这是一个练习,您可以通过以下方式找到解决方案 你自己),但这将是一个指数算法,其值为 O(2^N) 长度输入的最坏情况运行时间 N .

要查看示例中效率低下的原因,假设 输入是[x;y;z][x';y';z']x不同于x'lcs [x;y;z] [x';y';z']将进行两次递归调用,一次 lcs [y;z] [x';y';z']和一个lcs [x;y;z] [y';z'] 。但是那两个电话 每个人都会调用两个电话,lcs [z] [x';y';z']lcs [y;z] [y';z'] 对于第一个,和 lcs [y;z] [y';z']lcs [x;y;z] [z']为了 第二个。请注意,它们都进行了递归调用 lcs [y;z] [y';z'] ,因此将被计算两次。对于足够长的输入,其他子调用会重新计算任意高的时间。

避免这种低效率的解决方案是构建一个数据结构 每个结果只计算一次。传统的方法是 使用可变的二维矩阵来存储结果,但你不是 允许使用它。您可以使用函数式数据结构来存储 通过计算对应的列表列表来得出结果

[
  [lcs [x;y;z] [x';y';z']; lcs [x;y;z] [y';z']; lcs [x;y;z] [z']; lcs [x;y;z] [];]; 
  [lcs [y;z] [x';y';z'];   lcs [y;z] [y';z'];   lcs [y;z] [z'];   lcs [y;z] [];];
  [lcs [z] [x';y';z'];     lcs [z] [y';z'];     lcs [z] [z'];     lcs [z] [];];
  [lcs [] [x';y';z'];      lcs [] [y';z'];      lcs [] [z'];      lcs [] [];];
]

找到一种简单的递归方法来计算这个结果列表似乎 一个有趣的高级练习。例如,您可以递归地计算边 4 的这个“正方形”,方法是计算边 3 的右下角子正方形,然后折叠它(作为列表的列表)以计算结果正方形的左侧,然后折叠它的行(列表列表的头部)来计算结果正方形的顶边。更一般地,您可以定义一个函数 lcs_results xs ys需要两个长度为 M 的序列和N并返回 MxN list-of-list 对应于 lcs xs ys 计算的所有子结果,以这种方式组织。

但是,我认为您只是在寻找朴素的指数公式(同样,看起来像是一种教学 练习)。

关于arrays - ocaml lcs 没有像数组这样的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14882573/

相关文章:

list - 使用 foldl 和 foldr 反转 Scheme 中的列表

c++ - 类型 'const char*' 的参数与类型 'char*' 的参数不兼容

javascript - 访问数组内对象的值

java - 使 OcaIDE 在 Mac 上的 Eclipse 中工作

f# - 比较 F# 和 OCaml

regex - 检查字符串是否以 OCaml 中的某些文本结尾的最方便方法?

scala - 如何向左折叠 BigDecimal 列表? ("overloaded method + cannot be applied")

javascript - 获取数组中唯一序列的最短方法

java - 如何将多个不相关的int值添加到数组中

haskell - 您将如何在 Haskell 中使用 foldr 定义映射和过滤器?