【发布时间】:2017-12-29 07:36:02
【问题描述】:
了解基本概念后,以命令式风格编写动态编程 (DP) 问题就非常简单了,至少对于更简单的 DP 问题是这样。它通常涉及某种形式的表格,我们根据某些公式迭代填充。这几乎就是实现自下而上 DP 的全部内容。
让我们以Longest Increasing Subsequence (LIS) 作为一个简单而常见的示例,说明可以使用自下而上的 DP 算法解决的问题。
C++ 实现很简单(未经测试):
// Where A is input (std::vector<int> of size n)
std::vector<int> DP(n, 0);
for(int i = 0; i < n; i++) {
DP[i] = 1;
for(int j = 0; j < i; j++) {
if (A[i] > A[j]) {
DP[i] = std::max(DP[i], DP[j] + 1);
}
}
}
我们刚刚描述了“如何填充 DP”,这正是命令式编程的含义。
如果我们决定描述“什么是 DP”,这是一种更 FP 的思考方式,它会变得有点复杂。 这是解决此问题的示例 Scala 代码:
// Where A is input
val DP = A.zipWithIndex.foldLeft(Seq[Int]()) {
case (_, (_, 0)) => Seq(1)
case (d, (a, _)) =>
d :+ d.zipWithIndex.map { case (dj, j) =>
dj + (if (a > A(j)) 1 else 0)
}.max
}
老实说,这个 Scala 实现似乎不太习惯。它只是对命令式解决方案的一种翻译,添加了不变性。
我很好奇,处理这种事情的一般 FP 方式是什么?
【问题讨论】:
-
我不了解 scala,但是很多函数式编程库都有一个
memoize模式,它以透明的方式进行缓存。 -
是的,感谢您向我指出那个方向,将查找以了解更多信息。不过,乍一看,它似乎更适用于自上而下的 DP 算法?谢谢!
-
谢谢,但我正在寻找更通用的方法。
-
基本思想是将
DP表示为一个流,并声明一个生成它的递归函数。您可以从生成斐波那契数 stackoverflow.com/questions/9864497/… 的更简单的问题中获得启发。 -
很抱歉,但我认为这与 DP 无关。我认为您提供的链接上的解决方案根本没有任何记忆。
标签: scala functional-programming dynamic-programming purely-functional