当前位置: 首页 > 面试题库 >

功能范式中的动态编程

容磊
2023-03-14
问题内容

我正在研究Euler项目上的问题31,它问,使用1p,2p,5p,10p,20p,50p,1英镑(100p)和£任意数量的硬币来制作2英镑有多少种不同的方式2(200p)。

有递归解决方案,例如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)

尽管它运行速度足够快,但效率相对较低,调用了该f函数约560万次。

我看到有人用动态编程的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
,但是否有一种惯用的功能方法使用不可变的数据结构来做到这一点,最好具有相似的简洁性和性能?

在尝试以递归方式更新a List之前,我尝试并陷入困境,然后才决定我可能只是以错误的方式进行操作。


问题答案:

每当基于前一个元素计算数据列表的某些部分时,我都会想到Stream递归。不幸的是,这种递归不能在方法定义或函数内部发生,因此我不得不将一个函数转换为一个类以使其起作用。

class IterationForCoin(stream: Stream[Int], coin: Int) {
  val (lower, higher) = stream splitAt coin
  val next: Stream[Int] = lower #::: (higher zip next map { case (a, b) => a + b })
}
val coins = List(1, 2, 5, 10, 20, 50, 100, 200)
val result = coins.foldLeft(1 #:: Stream.fill(200)(0)) { (stream, coin) =>
  new IterationForCoin(stream, coin).next
} last

定义lower,并higher没有必要-我可以很容易地替换他们stream take coinstream drop coin,但我认为这是一个更清晰一点(和更有效)这种方式。



 类似资料:
  • 本文向大家介绍Android编程实现输入框动态自动提示功能,包括了Android编程实现输入框动态自动提示功能的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Android编程实现输入框动态自动提示功能。分享给大家供大家参考,具体如下: 关于AutoCompleteTextView的使用,我想大家并不陌生,对其设定上Adapter后系统便能自己识别与匹配了。近期 一个项目中,需要做到匹配通

  • 当按下按钮时,是否可以将可访问性焦点(Voiceover foriOS和Talkback for Android)移动到定义的小部件? 我尝试过在语义包中搜索,但我找不到一种方法来获得它。 让屏幕阅读器从头开始重新启动语义树就足够了。 我有一个包含3个页面和按钮,可以使用向后/向前移动。我想使用按钮(调用)进行更改时,将焦点移动到页面的开头。

  • 我试图创建一个重载函数,该函数将用对象的动态类型调用。我尽量做到这一点,而不干扰下面的实际类结构,因为我没有直接访问权限(即我无法添加虚拟方法等) 作为一个具体的例子,让我们考虑一个AST类结构,它看起来有点像这样: 我想编写一个函数act,它将ASTNode的一个实例作为参数,并根据其实际的动态类型执行不同的操作。电话是这样的 然后,我想根据ASTNode的动态类型采取行动。 但目前我无法调用,

  • 编程范式 Rust是一个多范式 (multi-paradigm) 的编译型语言。除了通常的结构化、命令式编程外, 还支持以下范式。 函数式编程 Rust使用闭包 (closure) 来创建匿名函数: let num = 5; let plus_num = |x: i32| x + num; 其中闭包plus_num借用了它作用域中的let绑定num。如果要让闭包获得所有权, 可以使用move关键字

  • PHP 是一个灵活的动态语言,支持多种编程技巧。这几年一直不断的发展,重要的里程碑包含 PHP 5.0 (2004) 增加了完善的面向对象模型,PHP 5.3 (2009) 增加了匿名函数与命名空间以及 PHP 5.4 (2012) 增加的 traits。 面向对象编程 PHP 拥有完整的面向对象编程的特性,包括类,抽象类,接口,继承,构造函数,克隆和异常等。 函数式编程 Functional P

  • 设计使用Blockly的应用程序时,有几种范例可供选择。这些选择应尽早考虑,因为它们会影响用户所需的功能块。 构造 许多Blockly应用程序用于描述配置,而不是可执行程序。配置应用程序通常从初始化工作空间上的一个根级别块开始。一个很好的例子是Blockly Developer Tools的Block Factory选项卡: var xml = '<xml><block type="factory