我在Scala中编写了这个函数来计算给定特定索引n的斐波那契数:
def fibonacci(n: Long): Long = {
if(n <= 1) n
else
fibonacci(n - 1) + fibonacci(n - 2)
}
但是,使用大型索引进行计算时效率不高。因此,我需要使用元组实现一个函数,这个函数应该返回两个连续的值作为结果。
有人可以给我任何暗示吗?我之前从未使用过Scala。谢谢!
答案 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=M
,x=0
,y=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