神奇的兔子序列(斐波那契数列)

14天阅读挑战赛

神奇的兔子序列

假设第1个月有1对刚诞生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去。那么,由1对初生兔子开始,12个月后会有多少对兔子呢?

:兔子数列即斐波那契数列,它的发明者是意大利数学家列昂纳多•斐波那契(Leonardo Fibonacci,1170—1250)。1202年,他撰写了《算盘全书》(《Liber Abaci》)一书,该书是一部较全面的初等数学著作。书中系统地介绍了印度—阿拉伯数码及其演算法则,介绍了中国的“盈不足术”;引入了负数,并研究了一些简单的一次同余式组。

案例分析

以1对新出生小兔子为例。

第1个月:小兔子1没有繁殖能力,所以还是1对。

第2个月:小兔子1进入成熟期,还是1对。

第3个月:小兔子1生了1对小兔子2,本月共有2对兔子。

第4个月:小兔子1又生了1对小兔子3,本月共有3对兔子。

第5个月:小兔子1又生了1对小兔子4,而在第3个月出生的小兔子2也生了1对小兔子5,本月共有5对兔子。

第6个月:小兔子1,2,3各生1对小兔子,本月共有8对兔子。

。。。

用图片表示为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oNdpEFmT-1666346510480)(C:\Users\iDoit\Desktop\兔子.jpg)]

因此可以推出:
n 当月的兔子对数 = n 上月兔子对数 + n 上上月兔子对数 n_{当月的兔子对数}=n_{上月兔子对数}+n_{上上月兔子对数} n当月的兔子对数=n上月兔子对数+n上上月兔子对数
其对应的斐波那契数列如下:
1 , 1 , 2 , 3.5 , 8 , 13 , 21 , 34 , . . . (1) 1, 1, 2, 3. 5, 8, 13, 21, 34,... \tag1 1,1,2,3.5,8,13,21,34,...(1)
其对应的递归表达式为
F ( n ) = { 1 , n = 1 1 , n = 2 F ( n − 1 ) + F ( n − 2 ) , n > 2 (2) F(n)=\begin{cases} 1 ,\quad n=1 \\ 1 ,\quad n=2 \\ F(n-1)+F(n-2) , \quad n>2 \end{cases} \tag2 F(n)= 1,n=11,n=2F(n1)+F(n2),n>2(2)
根据递归公式,我们可以设计出其对应的递归算法:

//递归的方式
fib(int n)
{
  if(n < 1)
  {
      return -1;
  }
  if(n == 1 || n == 2)     //对应递归表达式中n=1或n=2的情况
  {
      return 1;
  }
  return fib(n -1) + fib(n - 2);  //对应n>2的情况
}

下面我们分析一下它的时间复杂度,斐波那契数列的通项公式为(其推到过程可自行百度)
F ( n ) = 1 5 [ ( 1 + 5 2 ) n ( 1 − 5 2 ) n ] (3) F(n)=\frac{1}{\sqrt{5}} \Bigg[ \Bigg(\frac{1+{\sqrt{5}}}{2} \Bigg)^n \Bigg(\frac{1-{\sqrt{5}}}{2} \Bigg)^n \Bigg] \tag3 F(n)=5 1[(21+5 )n(215 )n](3)
当n趋近于无穷的时候,根据其通项公式分析可得,上例算法的时间复杂度为 O ( ( 1 + 5 2 ) n ) O((\frac{1+{\sqrt{5}}}{2} )^n ) O((21+5 )n),属于指数阶的算法。

根据递归公式设计出来的算法时间复杂度过大,影响实际应用的效率,我们不妨从式子(1)入手,从式子(1)可以发现:数列从第三项开始,数列中的每一项都是前两项之和,那我们的算法如果不采用迭代,直接使用数组,是否可以降低其时间复杂度。

//数组的方式
int fib(int n)
{
    if( n == 1 || n == 2{
        return 1;
    }
    int pre1 = 1;   //记录前一项
    int pre2 = 1;   //记录前二项 
    for(int i = 3, i <= n; i++)
    {
        int tmp = pre2 + pre1;
        pre2 = pre1;
        pre1 = tmp;
    }
    return pre1;
}

通过上例,可以明显的发现时间算法执行得次数的高阶项只剩n,其复杂度变为 O ( n ) O(n) O(n),时间复杂度大大降低。

我们对斐波那契序列进一步分析,根据公式(2)引入矩阵,可以归纳出公式(4):
[ F n + 2 F n + 1 ] = [ 1 11 0 ] [ F n + 1 F n ] = [ F 2 F 1 F 1 F 0 ] [ F n + 1 F n ] (4) \left[ \begin{matrix}F_{n+2} \\F_{n+1}\end{matrix}\right]=\left[ \begin{matrix}1 & 1 1 & 0 \end{matrix}\right] \left[ \begin{matrix} F_{n+1} F_{n}\end{matrix}\right]=\left[ \begin{matrix}F_{2} & F_{1}F_{1} & F_{0}\end{matrix}\right]\left[ \begin{matrix}F_{n+1} F_{n}\end{matrix}\right] \tag4 [Fn+2Fn+1]=[1110][Fn+1Fn]=[F2F1F1F0][Fn+1Fn](4)
其中 F 0 = 0 F_0=0 F0=0(为了分析方便,我们引入 F 0 = 0 F_0=0 F0=0),那么当n=1、2、3的时候会有
n = 1 时 − − − − − − > [ F 3 F 2 ] = [ F 2 F 1 F 1 F 0 ] [ F 2 F 1 ] \\n=1时------>\left[ \begin{matrix}F_{3}F_{2}\end{matrix}\right]= \left[ \begin{matrix}F_{2} & F_{1} \\F_{1} & F_{0}\end{matrix}\right]\left[ \begin{matrix}F_{2} F_{1}\end{matrix}\right] n=1>[F3F2]=[F2F1F1F0][F2F1]
n = 2 时 − − − − − − > [ F 4 F 3 ] = [ F 2 F 1 F 1 F 0 ] [ F 3 F 2 ] n=2时------>\left[ \begin{matrix}F_{4} F_{3}\end{matrix}\right]= \left[ \begin{matrix}F_{2} & F_{1} \\ F_{1} & F_{0}\end{matrix}\right]\left[ \begin{matrix}F_{3} F_{2}\end{matrix}\right] n=2>[F4F3]=[F2F1F1F0][F3F2]

n = 3 时 − − − − − − > [ F 5 F 4 ] = [ F 2 F 1 F 1 F 0 ] [ F 4 F 3 ] n=3时------>\left[ \begin{matrix}F_{5} F_{4}\end{matrix}\right]=\left[ \begin{matrix}F_{2} & F_{1} \\F_{1} & F_{0}\end{matrix}\right] \left[ \begin{matrix}F_{4} F_{3}\end{matrix}\right] n=3>[F5F4]=[F2F1F1F0][F4F3]
根据上面的式子我们可以得到
[ F n + 2 F n + 1 ] = [ 1 1 1 0 ] n [ F 1 F 1 ] = [ 1 1 1 0 ] n [ 1 1 ] (6) \left[ \begin{matrix}F_{n+2} \\F_{n+1}\end{matrix}\right]= \left[ \begin{matrix}1 & 1 \\1 & 0\end{matrix}\right]^{n}\left[ \begin{matrix}F_{1} \\F_{1}\end{matrix}\right]=\left[ \begin{matrix}1 & 1 \\1& 0\end{matrix}\right]^{n}\left[ \begin{matrix}1 \\1\end{matrix}\right]\tag6 [Fn+2Fn+1]=[1110]n[F1F1]=[1110]n[11](6)
由于 F n + 2 = F n + 1 + F n 、 F n + 1 = F n + F n − 1 F_{n+2}=F_{n+1}+F_{n}、F_{n+1}=F_{n}+F_{n-1} Fn+2=Fn+1+FnFn+1=Fn+Fn1,结合向量 [ 1 1 ] \left[ \begin{matrix} 1\\ 1 \end{matrix} \right] [11],则有
[ F n + 2 F n + 1 ] = [ F n + 1 F n F n F n − 1 ] [ 1 1 ] (7) \left[ \begin{matrix}F_{n+2} \\F_{n+1}\end{matrix}\right]=\left[ \begin{matrix}F_{n+1} & F_{n} \\F_{n} & F_{n-1}\end{matrix}\right]\left[ \begin{matrix}1 \\1\end{matrix}\right]\tag7 [Fn+2Fn+1]=[Fn+1FnFnFn1][11](7)

结合(6),我们可以假设
[ 1 1 1 0 ] n = [ F n + 1 F n F n F n − 1 ] \left[ \begin{matrix}1 & 1 \\1 & 0\end{matrix}\right]^{n}=\left[ \begin{matrix}F_{n+1} & F_{n} \\F_{n} & F_{n-1}\end{matrix}\right] [1110]n=[Fn+1FnFnFn1]

我们令 A = [ 1 1 1 0 ] A=\left[ \begin{matrix}1 & 1 \\1 & 0\end{matrix}\right] A=[1110],则
A n = [ F n + 1 F n F n F n − 1 ] (8) A^n=\left[ \begin{matrix}F_{n+1} & F_{n} \\F_{n} & F_{n-1}\end{matrix}\right] \tag8 An=[Fn+1FnFnFn1](8)
事实上,我们可以通过数学归纳法对(8)进行验证(验证过程可自行百度)我们的假设是对。那么我们可以基于(8)继续进行分析。

由(2)和(8)可得
A 2 m = A m ∗ A m = [ F 2 m + 1 F 2 m F 2 m F 2 m − 1 ] = [ F m + 1 F m F m F m − 1 ] ∗ [ F m + 1 F m F m F m − 1 ] = [ F m + 1 2 + F m 2 F m ( F m + 2 F m − 1 ) F m ( F m + 2 F m − 1 ) F m 2 + F m − 1 2 ] (9) A^{2m}=A^m*A^m =\left[ \begin{matrix}F_{2m+1} & F_{2m} \\F_{2m} &F_{2m-1}\end{matrix}\right]=\left[ \begin{matrix}F_{m+1} & F_{m} \\F_{m} & F_{m-1}\end{matrix}\right]* \left[ \begin{matrix}F_{m+1} & F_{m} \\F_{m} & F_{m-1}\end{matrix}\right]\\=\left[ \begin{matrix}F_{m+1}^2+F_m^2 & F_{m}(F_m+2F_{m-1}) \\F_{m}(F_m+2F_{m-1}) & F_{m}^2+F_{m-1}^2\end{matrix}\right]\tag9 A2m=AmAm=[F2m+1F2mF2mF2m1]=[Fm+1FmFmFm1][Fm+1FmFmFm1]=[Fm+12+Fm2Fm(Fm+2Fm1)Fm(Fm+2Fm1)Fm2+Fm12](9)
由(9)可得
F 2 m + 1 = F m + 1 2 + F m 2 (10) F_{2m+1}=F_{m+1}^2+F_m^2 \tag{10} F2m+1=Fm+12+Fm2(10)

F 2 m = F m ( F m + 2 F m − 1 ) (11) F_{2m}=F_{m}(F_m+2F_{m-1}) \tag{11} F2m=Fm(Fm+2Fm1)(11)

因此,我们可以判断n的奇偶性,来使用不同的计算方式,对应的代码如下:

//奇偶的方式
int fib(int n)
{
    if(n == 1 || n == 2)
    {
        return 1;
    }
    int k = (n & 1) == 1 ? (n + 1) /2 : n / 2;
    return (n & 1) == 1 ? (fib(k) * fib(k) + fib(k - 1) * fib( k- 1)) 
                        : fib(k - 1)) : (2 * fib(k - 1) + fib(k)) * fib(k);
}

接下来我们分析一下该算法的时间复杂度,以 F ( 5 ) F(5) F(5)为例。

						fib(5)   
                     /         \
               fib(3)          fib(2)   
             /        \              
         fib(2)      fib(1)        

通过上面 F ( 5 ) F(5) F(5)的例子,我们可以看到该算法明显的降低了 F ( n ) F(n) F(n)的时间复杂度,其每次以n减半的效率迭代,因此其时间复杂度为 O ( l o g n ) O(logn) O(logn)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艰默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值