【发布时间】:2011-10-02 02:36:06
【问题描述】:
我正在查看 Project Euler 上的 Problem thirty one,它询问,使用任意数量的 1 便士、2 便士、5 便士、10 便士、20 便士、50 便士、1 英镑(100 便士)的硬币有多少种不同的方法可以赚取 2 英镑) 和 2 英镑 (200 便士)。
有递归解决方案,例如 Scala 中的这个(感谢 Pavel Fatin)
def f(ms: List[Int], n: Int): Int = ms match {
case h :: t =>
if (h > n) 0 else if (n == h) 1 else f(ms, n - h) + f(t, n)
case _ => 0
}
val r = f(List(1, 2, 5, 10, 20, 50, 100, 200), 200)
虽然它运行得足够快,但效率相对较低,调用了大约 560 万次 f 函数。
我看到其他人用 Java 动态编程的解决方案(感谢来自葡萄牙的 wizeman)
final static int TOTAL = 200;
public static void main(String[] args) {
int[] coins = {1, 2, 5, 10, 20, 50, 100, 200};
int[] ways = new int[TOTAL + 1];
ways[0] = 1;
for (int coin : coins) {
for (int j = coin; j <= TOTAL; j++) {
ways[j] += ways[j - coin];
}
}
System.out.println("Result: " + ways[TOTAL]);
}
这样效率更高,只通过内循环 1220 次。
虽然我显然可以使用 Array 对象将其或多或少逐字翻译成 Scala,但是否有一种惯用的函数式方法可以使用不可变数据结构来做到这一点,最好具有类似的简洁性和性能?
我曾尝试递归更新List,但在决定我可能只是以错误的方式接近它之前陷入困境。
【问题讨论】:
-
我看了 Scala 版本 1 分钟,知道它是如何工作的。看了Java一5分钟,还是不知道怎么用。对我来说,这是一个很好的例子,表明函数式并不比命令式复杂。
-
@huynhjl 但是,除了查看函数式和迭代式算法之外,您还需要查看规范和优化的算法。
标签: java scala functional-programming dynamic-programming