Fibonacci序列快速实现

时间:2013-11-05 21:24:28

标签: scala fibonacci

我在Scala中编写了这个函数来计算给定特定索引n的斐波那契数:

 def fibonacci(n: Long): Long = {
 if(n <= 1) n
 else
   fibonacci(n - 1) + fibonacci(n - 2)     
} 

但是,使用大型索引进行计算时效率不高。因此,我需要使用元组实现一个函数,这个函数应该返回两个连续的值作为结果。

有人可以给我任何暗示吗?我之前从未使用过Scala。谢谢!

4 个答案:

答案 0 :(得分:1)

这个问题应该是数学。

Fibonacci序列有一个明确的公式。如果您需要计算n的Fibonacci数而不使用之前的数,则速度要快得多。你在这里找到它(比奈的公式):http://en.wikipedia.org/wiki/Fibonacci_number

答案 1 :(得分:1)

这是一个简单的尾递归解决方案:

def fibonacci(n: Long): Long = {
  def fib(i: Long, x: Long, y: Long): Long = {
    if (i > 0) fib(i-1, x+y, x)
    else x
  }
  fib(n, 0, 1)
}

您发布的解决方案需要指数时间,因为它会在每一步创建两个递归调用树(fibonacci(n - 1)fibonacci(n - 2))。通过简单地跟踪最后的两个数字,您可以递归计算答案而无需重复计算。


  

你能解释中间部分,为什么(i-1, x+y, x)等。抱歉,如果我要求太多,但我不想复制和粘贴代码而不知道它是如何工作的。

这很简单 - 但我对变量名称的选择不当可能会让人感到困惑。

  • i只是一个反击,说明我们还剩下多少步骤。如果我们正在计算 Mth (我使用M,因为我已经在我的代码中使用了n)Fibonacci编号,那么i告诉我们在达到 Mth 术语之前还有多少术语需要计算。
  • x是Fibonacci序列中的 mth 术语,或 F m (其中m = M - i)。
  • y是Fibonacci序列中的m-1th项,或 F m-1

因此,在第一次致电fib(n, 0, 1)时,我们有i=Mx=0y=1。如果你查找bidirectional Fibonacci sequence,你会看到F 0 = 0而F -1 = 1,这就是为什么{{1} }和x=0在这里。

在下一次递归调用y=1上,我们将fib(i-1, x+y, x)作为下一个x+y值。这直接来自定义:

F n = F n-1 + F n-2

我们将x作为下一个x项,因为我们当前的F n-1 与F n-2 相同下一学期。

在每一步我们减少y,因为我们离最终答案更近一步。

答案 2 :(得分:0)

我假设您没有以前计算中保存的值。如果是这样,使用黄金比率而不是递归定义使用直接公式会更快。公式可以在the Wikipedia page for Fibonnaci number

中找到
floor(pow(phi, n)/root_of_5 + 0.5)

其中phi = (1 + sqrt(5)/2)

我不了解Scala中的编程。我希望有人在SO上将我的伪代码升级为实际的Scala代码。

答案 3 :(得分:0)

<强>更新

这是另一个使用Streams的解决方案,如下所示(免费获取 Memoization ),但更直观(又名:不使用fibs Stream上的zip / tail调用):

val fibs = Stream.iterate( (0,1) ) { case (a,b)=>(b,a+b)  }.map(_._1) 

产生与以下相同的输出:

fibs take 5 foreach println 

Scala通过Streams支持Memoizations,这是一个惰性列表的实现。这非常适合Fibonacci实现,实际上在Scala Api for Streams中作为示例提供。引用这里:

import scala.math.BigInt
object Main extends App {

  val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }

  fibs take 5 foreach println
}

// prints
//
// 0
// 1
// 1
// 2
// 3