【问题标题】:Tail Recursion Fibonacci尾递归斐波那契
【发布时间】:2014-04-02 09:43:13
【问题描述】:

如何在 O(n) 中实现没有循环运行的递归斐波那契函数?

【问题讨论】:

  • 你知道如何得到第三个斐波那契数吗?第四?第五?
  • “它必须调用一个递归辅助函数”——什么?为什么?迭代方法要容易得多。我想他们想要迭代版本循环的递归公式。
  • @Mat.S:“不允许线性”是什么意思?
  • @user2357112 抱歉,这些只是规格。我不能使用任何循环,但它仍然必须是线性的。
  • 返回两个斐波那契数。

标签: python big-o fibonacci


【解决方案1】:

通常我会反对发布这样的家庭作业问题的答案,但到目前为止发布的所有内容似乎都过于复杂了。正如上面的 cmets 所说,您应该像迭代一样使用递归来解决问题。

这是迭代解决方案:

def fib(n):
  a, b = 0, 1
  while n > 0:
    a, b = b, a+b
    n -= 1
  return a

这是一个等效的递归解决方案:

def fib(n):
  def fib_help(a, b, n):
    return fib_help(b, a+b, n-1) if n > 0 else a
  return fib_help(0, 1, n)

请注意,在这两种情况下,我们实际上都计算了 Fn+1,但返回 Fn 作为结果。这与你得到的“提示”非常吻合。

我希望您花时间比较这两种解决方案,并说服自己它们是等价的。了解如何将迭代解决方案转换为等效的递归解决方案(反之亦然)是一项很好的开发技能。

【讨论】:

  • 尾递归形式,嗯?这是另一种好方法。在 Scheme 或其他函数式语言中非常有用的技能,并且很高兴知道它为您提供的视角。并不总是 Python 中最实用的转换,但也不是提示想要的解决方案。
  • 如果您将 a 和 b 作为默认参数提供给 fib,则无需 fib_help:def fib(n, a=0, b=1):return fib(n-1, b, a+b) if n > 0 else a
【解决方案2】:

用于查找第 n 个斐波那契数的 Scala 代码。 更多关于尾递归的信息http://nerds.logdown.com/posts/1406258-n-th-fibonacci-number

object Main {
     def main(args: Array[String]) {
        println(fib(9));
        println(fib(8));
        println(fib(7));
        println(fib(6));
        println(fib(5));
        println(fib(4));
        println(fib(3));
        println(fib(2));
        println(fib(1));
        println(fib(0));
      }
      def fib(n: Int): Int = {
        def fib(n: Int, p :Int, c: Int): Int ={
          if (n == 0) return -1; // undefined
          if (n == 1) return p;
          fib(n-1, c, p + c)
        }
        fib(n, 0, 1);
      }
    }

【讨论】:

    【解决方案3】:

    如果有人正在寻找 JavaScript 解决方案:

    function _fib(n, left, right) {
      switch (n) {
        case 0: return 0
        case 1: return right
        default: return _fib(n - 1, right, left + right)
      }
    }
    
    function fib(n) {
      return _fib(n, 0, 1)
    }
    

    通过尾调用优化在 O(n) 时间和 O(1) 空间中运行。

    【讨论】:

      【解决方案4】:

      要在线性时间内解决这个问题,您必须使用一种称为记忆化的动态编程技术。

      伪代码中的斐波那契算法,使用记忆化,如下所示:

      memoryMap[n]
      
      func fib(int n)
          if (n is in memoryMap) then
              return memoryMap[n]
          if (n <= 1) then
              memoryMap[n] = n
          else
              memoryMap[n] = fib(n-1) + fib(n-2)
      
          return memoryMap[n]
      

      解释一下,每次调用 fib(x) 后,您都将结果存储在内存映射中。对于每个后续调用,对 fib(x) 的所有查找都是免费的:也就是说,在内存中查找结果只需 O(1) 时间。

      【讨论】:

      • 这是一种方法,也是我想到的第一种方法,但不是预期的解决方案。有多少是好是坏是见仁见智的问题,但如果 OP 使用它,我建议 OP 也弄清楚并提交预期的解决方案。
      • 再读一遍,很明显正确的解决方案是尾递归。但是话又说回来,它仍然没有多大意义,因为 Python 甚至不支持尾递归消除。
      • 即使没有尾递归也有意义,因为它只使用 n 递归调用,应该适合 fib 的堆栈。将其与朴素的递归 fib(n) = fib(n-1) + fib(n-2) if n &gt;1 else n 进行比较
      • 我觉得这个 memoization 是一件很自然的事情,为了避免多次计算,你将这些计算结果保存在某个地方,在那里你可以查看结果将来。在我看来,称其为“动态编程”为非常简单的事情增加了很多动力。不使用突变或分配的版本会很有趣。
      猜你喜欢
      • 1970-01-01
      • 2010-12-03
      • 2021-11-27
      • 2017-11-18
      • 2014-01-08
      • 2011-12-14
      • 2012-11-29
      • 2018-04-10
      相关资源
      最近更新 更多