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=11,n=2F(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(n−1)+F(n−2),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)=15[(1+52)n(1−52)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(21−5​​)n](3)
当n趋近于无穷的时候,根据其通项公式分析可得,上例算法的时间复杂度为O((1+52)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):
[Fn+2Fn+1]=[1110][Fn+1Fn]=[F2F1F1F0][Fn+1Fn](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+2​Fn+1​​]=[1​11​0​][Fn+1​Fn​​]=[F2​​F1​F1​​F0​​][Fn+1​Fn​​](4)
其中F0=0F_0=0F0​=0(为了分析方便,我们引入F0=0F_0=0F0​=0),那么当n=1、2、3的时候会有
n=1时−−−−−−>[F3F2]=[F2F1F1F0][F2F1]\\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时−−−−−−>[F3​F2​​]=[F2​F1​​F1​F0​​][F2​F1​​]
n=2时−−−−−−>[F4F3]=[F2F1F1F0][F3F2]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时−−−−−−>[F4​F3​​]=[F2​F1​​F1​F0​​][F3​F2​​]

n=3时−−−−−−>[F5F4]=[F2F1F1F0][F4F3]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时−−−−−−>[F5​F4​​]=[F2​F1​​F1​F0​​][F4​F3​​]
根据上面的式子我们可以得到
[Fn+2Fn+1]=[1110]n[F1F1]=[1110]n[11](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+2​Fn+1​​]=[11​10​]n[F1​F1​​]=[11​10​]n[11​](6)
由于Fn+2=Fn+1+Fn、Fn+1=Fn+Fn−1F_{n+2}=F_{n+1}+F_{n}、F_{n+1}=F_{n}+F_{n-1}Fn+2​=Fn+1​+Fn​、Fn+1​=Fn​+Fn−1​,结合向量[11]\left[ \begin{matrix} 1\\ 1 \end{matrix} \right][11​],则有
[Fn+2Fn+1]=[Fn+1FnFnFn−1][11](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+2​Fn+1​​]=[Fn+1​Fn​​Fn​Fn−1​​][11​](7)

结合(6),我们可以假设
[1110]n=[Fn+1FnFnFn−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] [11​10​]n=[Fn+1​Fn​​Fn​Fn−1​​]

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

由(2)和(8)可得
A2m=Am∗Am=[F2m+1F2mF2mF2m−1]=[Fm+1FmFmFm−1]∗[Fm+1FmFmFm−1]=[Fm+12+Fm2Fm(Fm+2Fm−1)Fm(Fm+2Fm−1)Fm2+Fm−12](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=Am∗Am=[F2m+1​F2m​​F2m​F2m−1​​]=[Fm+1​Fm​​Fm​Fm−1​​]∗[Fm+1​Fm​​Fm​Fm−1​​]=[Fm+12​+Fm2​Fm​(Fm​+2Fm−1​)​Fm​(Fm​+2Fm−1​)Fm2​+Fm−12​​](9)
由(9)可得
F2m+1=Fm+12+Fm2(10)F_{2m+1}=F_{m+1}^2+F_m^2 \tag{10} F2m+1​=Fm+12​+Fm2​(10)

F2m=Fm(Fm+2Fm−1)(11)F_{2m}=F_{m}(F_m+2F_{m-1}) \tag{11} F2m​=Fm​(Fm​+2Fm−1​)(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(logn)O(logn)O(logn)。

神奇的兔子序列(斐波那契数列)相关推荐

  1. 有趣的兔子(斐波那契数列)

    有趣的兔子(斐波那契数列) 如果每对兔子每月繁殖一对子兔,而子兔在出生后第二个月就有生殖能力,试问一对兔子一年能繁殖多少对兔子?可以这样思考:第一个月后即第二个月时,1对兔子变成了两对兔子,其中一对是 ...

  2. Java编程练习之:有关兔子的斐波那契数列问题解析

    文章目录 1. 题目 2. 思路 3. 代码 4. 运行结果 1. 题目 古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的 ...

  3. 古老递归问题(兔子版本斐波那契数列)

    题目: 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 首先,我目前还是菜鸟,若解答有问题,直接评论戳我吧! 这是 ...

  4. 兔子生兔子问题(斐波那契数列)

    问题描述: 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少 分析: 这道题我们可以把兔子分为三个阶段,幼崽.成年,生 ...

  5. 兔子问题(斐波那契数列)

    有这样一个有趣的"兔子问题":"假定一对大兔子每月能生一对小兔子,且每对新生的小兔子经过一个月可以长成一对大兔子,具备繁殖能力,如果不发生死亡,且每次均生下一雌一雄,问一 ...

  6. 递归优化为递推:数组/临时变量-计算兔子(斐波那契数列)

    题目 有一对兔子,从出生后第3个月起每个月都生一对兔子,一对小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第n个月(n<=50)的兔子总数为多少对? 题解 多次递归 /* 找规律: ...

  7. 兔子c语言程序,可爱的C语言程序。....兔子问题...斐波那契数列

    输入月数(少于40): 40 M.1:         1M.2:         1M. 3:         2 M. 4:         3M. 5:         5M. 6:       ...

  8. 【趣学算法】神奇的兔子序列(斐波那契数列)

    14天阅读挑战赛 努力是为了不平庸~ 算法学习有些时候是枯燥的,这一次,让我们先人一步,趣学算法!欢迎记录下你的那些努力时刻(算法学习知识点/算法题解/遇到的算法bug/等等),在分享的同时加深对于算 ...

  9. 斐波那契数列---兔子繁殖题

    斐波那契数列-兔子繁殖题 如果说兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来.假设所有兔子都不会死去,能够一直干下去,那么一年以后可决繁殖多少对兔子呢? 斐波那契数列的迭代实现 ...

  10. 兔子生兔子之递归问题(递归实现斐波那契数列)

    今天给大家带来一个经典题,斐波那契数列,题目如下: //题目:有一对兔子,从出生后第3个月起每个月都生一对兔子,//小兔子长到第三个月后每个月又生一对兔子.假如兔子都不死,要求根据输入的月份输出对应兔 ...

最新文章

  1. linux系统源码安装教程,linux之源码包安装步骤
  2. Job for docker.service failed because the control process exited with error code. See systemctl sta
  3. springcloud 与springboot的依赖关系以及版本的选择
  4. 【渝粤教育】广东开放大学 电子商务(本) 形成性考核 (21)
  5. #Pragma Pack(n)与内存分配 pragma pack(push,1)与#pragma pack(1)的区别
  6. CS224n研究热点5 图像对话
  7. Confluence或JIRA验证码乱码的问题
  8. 我的十年创作之路(三)——书稿创作经验谈
  9. 数据库设计的几个建议
  10. 十年PHP架构师的成长之路,程序员必备
  11. liujian的效果图
  12. 今日小程序推荐:毒舌电影
  13. 如何看错误日志,尤其是Caused by类的日志?
  14. TM1650数码管驱动芯片
  15. 深圳宝安周边公司出行团建户外一日游
  16. 2022暑假牛客多校1 (A/G/D/I)
  17. Linux的一些快捷键
  18. 电商实训四:网络营销方案设计及实施
  19. DL4J解决Score NaN
  20. 深度学习中的不确定性:What Uncertainties Do We Need in Bayesian Deep Learning for Computer Vision

热门文章

  1. 【C++】 Swan学院社团招新(PTA)
  2. Linux - 拨号上网
  3. 服务器主板显示不了独立显卡,独立显卡故障——如何才知道显卡和主板不兼容...
  4. October 20th 2017 Week 42nd Friday
  5. Unity3d实现双人网络坦克大战
  6. Redis 开机自启
  7. 将多个excel合并到同一个Excel中的多个sheet页,并且以原表名命名sheet页(Office)
  8. Oracle中select SEQ_YX.nextval from dual是什么意思
  9. IIBA - CBAP考试感悟
  10. P2320 [HNOI2006] 鬼谷子的钱袋