在这篇文章中,我们将实现不同的算法来计算第n个斐波那契数。
目录
斐波那契数的介绍
在数学领域,斐波那契数(表示为Fn)是一个序列,其中每个数字都是前面两个数字之和。
这个序列被称为斐波那契数列。它通常从0和1开始,尽管我们可以从1和1或者1和2开始。从0和1开始,序列中接下来的几个值是。
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
斐波那契数列的递归公式是:-
Fn = Fn-1 + Fn-2
在OpenGenus的这篇文章中,我们将使用不同的方法来实现一种算法,以计算上述斐波那契数列中从0、1开始的第n个数字。
使用循环
我们可以使用循环来寻找第n个斐波那契数,方法是将前两个数字初始化为变量,并从3到n进行循环,其中每项是前两项的总和。
实现该算法
我们将定义一个接受整数n的函数。在函数内部,我们初始化两个变量a=0和b=1,然后我们将检查n=1或n=2的情况,如果n=1则返回a,如果n=2则返回b。如果n不是1或2,则使用从3到n的for循环,我们将计算出下一个斐波那契数,并将其存储起来,将a和b增加到斐波那契序列的下一个值。当循环结束时,第二个变量b将存储或指向第n个数值,现在我们只需返回b。
使用循环计算第n个斐波那契数的函数的Python代码
def Fib(n):
a = 0
b = 1
if n == 1:
return a
elif n == 2:
return b
else:
for i in range(3,n+1):
c = a + b
a = b
b = c
return b
n = 5
print(Fib(n))
输出。
3
在上面的算法中,函数 Fib 接受一个整数值 n 作为参数。如果n是1,它返回第一个初始化为0的数字a,如果n是2,它返回第二个1的数字b,否则,它遍历3到n(含),并通过添加a和b计算下一个项,使a和b成为第1次迭代的前两个项。该算法循环计算从1到n的每个数字,因此,该算法的时间复杂度为O(n)。由于该算法使用常数空间,因此该算法的空间复杂度为O(1)。
使用递归
我们可以通过使用斐波那契数列的递归公式Fn = Fn-1 + Fn-2,来使用递归来找到第n个斐波那契数。
实现该算法
我们将定义一个函数,该函数接收一个整数值n。在主体内部,我们将检查n=1或n=2的基本情况,如果n=1则返回0,如果n=2则返回1。如果n既不是1也不是2,那么使用递归方法,我们将通过两次调用函数来返回前两个项的和,一次是参数n-1,另一次是参数n-2。
使用递归计算第n个斐波那契数的Python函数代码
def Fib(n):
if n == 1 :
return 0
if n == 2:
return 1
else:
return Fib(n-1) + Fib(n-2)
n = 6
print(Fib(n))
输出:输出:
5
在上述算法中,函数 Fib 将一个整数值 n 作为参数,如果 n 是 1 则返回 0,如果 n 是 2 则返回 1,否则返回递归句 Fib(n-1) + F(n-2)。这个函数递归计算每一个条款,直到遇到一个基本情况,即n=1,n=2。因此,这也有一个线性时间复杂度,O(n)。这个算法在每一步都对前两个值运行两次函数。
因此,这个函数的时间复杂度是O(2n)。如果我们考虑到函数调用栈的大小,这个算法的空间复杂度为O(n),否则它的空间复杂度为O(1)。
使用记忆化
这种方法类似于递归方法,但在每个递归步骤中存储数值,以尽量减少重复计算相同参数的函数。
实现该算法
我们将定义一个函数,它需要一个整数值n和一个默认参数memoize来存储基本条件。在正文中,我们将检查n是否在memoize中,如果memoize包含n,那么将返回键n的值,否则将使用递归方法计算第n个键的值,并从memoize返回第n个键的值。
使用动态编程的memoization技术计算第n个斐波那契数的函数的Python代码
def Fib(n, memoize={1: 0, 2: 1}):
if n in memoize:
return memoize[n]
else:
memoize[n] = Fib(n-1, memoize) + Fib(n-2, memoize)
return memoize[n]
n = 5
print(Fib(n))
输出:输出:
3
在上面的算法中,函数 Fib 需要一个整数 n 作为参数,以及一个默认的名为 memoize 的字典类型的参数,其中包含基数情况。在函数的主体中,我们检查整数n是否在memoize中,如果是,则返回映射到memoize中键n的值,否则,使用递归公式计算值,并将映射到键n的值存储在字典中,以便以后在递归步骤中使用,并返回计算的值。
这种算法减少了许多步骤,并以线性时间复杂度O(n)运行,与递归方法相比好得多。由于该算法存储了所有小于等于n的斐波那契数,所以它的空间复杂度为O(n)。
使用数学方法
我们可以使用数学方法来寻找第n个斐波那契数,方法是使用常数系数的二阶线性同质递归关系的概念。这里我们将使用Binet的斐波纳契数公式。
推导出Binet的公式
斐波那契递推关系Fn = Fn-1 + Fn-2的特征多项式是:
x2 = x + 1
特征方程的解是:
ϕ = (1+√5)/2
ψ = (1-√5)/2
所以斐波那契数列的封闭公式必须是这样的:
fn = ujn + vψn
现在我们使用递归的边界条件,即f0=0和f1=1,这意味着我们必须求解系统
0 = uj0 + vψ0
1 = uj1 + vψ1
第一个方程简化为u = -v,将其代入第二个方程,就可以得到:
1 = u((1+√5)/2)- u((1-√5)/2)
u = 1/√5
v = -1/√5
因此,第n个斐波那契公式为:
Fn = ( ϕn-1 - ψn-1 ) / √5
实现该算法
我们将定义一个接受整数值n的函数。在函数体中,我们将存储常数(1+√5)/2和(1-√5)/2,用于我们的公式表达。然后该函数将返回Binet公式的底线。在这里,我们使用底线来获得所需的结果,因为Binet公式返回的是近似值。
使用数学方法计算第n个斐波那契数的Python函数代码
def Fib(n):
phi1 = (1 - 5 ** 0.5) / 2
phi2 = (1 + 5 ** 0.5) / 2
return (phi2**(n-1) - phi1**(n-1)) // (5**0.5)
n = 5
print(Fib(n))
输出:
3
在这个算法中,我们把递推关系Fn = Fn-1 + Fn-2的特征方程的解作为phi1和phi2。然后我们确定第n个斐波那契数的一般公式,即取phi1和phi2的(n-1)次幂之差的底限值,以及5的平方根。
公式如下:
Floor ( ( phi2n-1 - phi1n-1 ) / (50.5)
注意,这里我们使用了整数除法,Pythonic符号,这与计算除法后得到的数值的下限相似。
这个算法需要O( log(n))时间,因为指数化步骤需要log(n)时间。由于该算法只存储了两个常数phi1和phi2,因此其空间复杂度为O(1)。
通过OpenGenus的这篇文章,你一定对计算nᵗʰ斐波那契数的不同方法有了完整的了解。