对于兔子问题的鼎鼎大名,相信很少有人没听过吧!为了完整性还是再说一下题目吧!

题目描述:已知一对兔子每一个月可以生一对小兔子,而一对兔子出生后.第三个月开始生小兔子假如一年内没有发生死亡,则一对兔子开始,第N个月后会有多少对?

这道题所描述的就是斐波那契数列啦!这里以一对为单位,那么,从第一个月开始,每个月总共的兔子数量就是1,1,2,3,5,8,13......可以看出前两个月为1,从第三个月开始,当月的数量为前两个月数量之和,所以可以形成公式f(n)=f(n-1)+f(n-2)(n>2)同时f(1)=1,f(2)=1。

关于这道题的实现由很多种方法,那么接下来笔者就从O(2^n)说起。

1.时间复杂度O(2^n)

#include<iostream>
using namespace std;
int Fibonacci(int fib)
{if(fib<=0){return 0;}else if(fib==1||fib==2){return 1;}else{return Fibonacci(fib-1)+Fibonacci(fib-2);//当前月等于前一个月的数量加上前两个月的数量}
}
int main()
{int num,result;cin>>num;//输入第几个月result=Fibonacci(num);cout<<result;return 0;
}

那为什么说此方法的时间复杂度是O (2^n)呢?

下图描述了整个递归过程,可以看出最终形成了类似一个二叉树,每个节点都有访问,那么时间复杂度,就明显看的出来了

上图也同样暴露出上述递归算法的问题所在,就是同一个数多次访问,明明其它地方计算过了,却还会重复计算。

接下讲述另一种方法,时间复杂度有较大改善

2.时间复杂度O(n)

#include<iostream>
using namespace std;
int Fibonacci(int fib)
{int res=1;int pre=1;int temp=0;if(fib<=0){return 0;}else if(fib==1||fib==2){return 1;}else{for(int i=3;i<=fib;i++){temp=res+pre;pre=res;res=temp;}return res;}
}
int main()
{int num,result;cin>>num;//输入第几个月result=Fibonacci(num);cout<<result;return 0;
}

很明显可以看出整个时间消耗在i 在3  - fib 的循环中,时间复杂度O(n),自此斐波那契数列已经达到线性,那么,时间复杂度有没有可能更小呢?

答案是肯定的。

3.时间复杂度O(log(n)) (本方法学习自牛客网,左程云(左神))

当然在讲述这种方法之前,必须要介绍一下线性代数的知识,在线性代数中下图中的等式是恒成立的。

具体怎么证明,直接说,不会,但是这个公式确实整个算法的核心,由上面的公式我们可以列出如下图的公式并且得出a,b,c,d的值。
那么,下图所示的推导过程也就很容易理解了
现在想求F(n)整个问题就变成了一个矩阵的(n-2)次方了,那么一个矩阵的(n-2) 次,实现起来怎么达到 O(log(n))?
以下引用左神原话:
而求矩阵N次⽅方的问题,明显是一个更够在O(logN)时间内解决的问题。为了表述方便,我们现在用求一个整数N次方的例子来说明,因为只要理解了如何在O(logN)的时间复杂度内求整数N次方的问题,对于求矩阵N次方的问题是同理的,区别是矩阵乘法和整数乘法在细节上有些不一样,但是对于怎么乘更快,两者的道理相同。
假设一个整数是10,如何最快的求解10的75次方。
1,75的二进制形式为1001011。
2,10的75次方=(10^64) * (10^8) * (10^2) * (10^1)。在这个过程中,我们先求出10^1,然后根据10^1求出10^2,再根据10^2求出10^4,...,最后根据10^32求出10^64次方,即75的二进制形式总共有多少位,我们就使用了几次乘法。
3,在步骤2进行的过程中,把应该累乘的值乘起来即可。10^64、10^8、10^2、10^1应该累乘起来,因为64、8、2、1对应到75的二进制中,相应的位上是1。而10^32、10^16、10^4不应该累乘,因为32、16、4对应到75的二进制中,相应的位上是0。
整体程序实现如下:
#include<iostream>
using namespace std;
int base[4] = { 1, 1, 1, 0 };
int result[4] = { 1, 0, 0, 1 };//将结果矩阵初始为单位阵Evoid MatrixMulti(int ba[4], int re[4], bool flag)// 这个函数实现其实应该用二维数组,原谅我这一生放纵不羁爱偷懒
{int temp[4] = { 0 };temp[0] = ba[0] * re[0] + ba[1] * re[2];temp[1] = ba[0] * re[2] + ba[1] * re[3];temp[2] = ba[2] * re[0] + ba[3] * re[2];temp[3] = ba[2] * re[1] + ba[3] * re[3];if (flag){for (int i = 0; i < 4; i++){result[i] = temp[i];}}else{for (int i = 0; i < 4; i++){base[i] = temp[i];}}
}
int main()
{int month;cin >> month;if (month < 1){cout << 0 << endl;return 0;}if (month == 1||month==2){cout << 1 << endl;return 0;}month-=2;for (; month != 0; month >>= 1)//此for循环是实现O(log(n))的关键{if (month & 1){MatrixMulti(base, result,true);}MatrixMulti(base, base,false);}cout << result[0] + result[2];return 0;
}

那么到这就完了么,时间复杂度还能不能再降低呢?答案是,能。


4.时间复杂度O(1) 
之所以能实现O(1) 请感谢数学的伟大吧,竟然有人计算出了斐波那契数列的通项公式 
那么时间复杂度必须是O(1)啊!先不着急程序实现,我们想想,如果问我们怎么判断一个数是不是斐波那契数呢?同样也有 O(1)的解法:判断一个数是否是一个斐波那契数当且仅当5N^2+4或5N^2-4是平方数。我只能再一次感叹数学的伟大,所以数学系的经常来抢计算机的饭碗,我们却无能为力啊!下面给出代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void main()
{double n;scanf("%lf",&n);printf("%d\n", (int)((pow(((1 + sqrt(5)) / 2), n) - pow(((1 - sqrt(5)) / 2), n)) / sqrt(5)));return 0;
}

结语:看见最后这几行代码我想会有很多人哭晕在厕所吧!我先哭一会!!!

兔子问题---细说斐波那契数列相关推荐

  1. 兔子繁殖问题 斐波那契数列 java实现

    兔子繁殖问题 斐波那契数列 java实现 问题描述 一对兔子,从出生后第3个月起每个月都生一对兔子. 小兔子长到第3个月开始每个月又生一对兔子. 假如兔子都不死, 请问第1个月出生的一对兔子,第n个月 ...

  2. 兔子问题,斐波纳契数列

    题目:古典问题(斐波纳契数列):有一对兔子,从出生后3个月起每个月都生一对兔子,小兔子长到第三个月又会生一对兔子,假如兔子都不死,问每个月兔子总数? 分析规律:1 1 2 3 5 8 13 21- 从 ...

  3. JavaScript算法(实例八)递归计算每个月的兔子总数【斐波那契数列】

    古典问题:有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问每个月的兔子总数为多少? 思考这道题的时候,如果你简单的推算一下,会发现每个月的兔 ...

  4. matlab兔子繁殖问题,斐波那契数列在《疯狂动物城》兔子繁衍中的应用

    摘    要: 计算思维的构建有助于帮助学生将实际问题转换为透明易懂的框架算法, 并借助计算机解决.以电影<疯狂动物城>中的兔子繁殖问题为例, 引出斐波那契数列, 引导学生将数学表达式转化 ...

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

    #题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子, #假如兔子都不死,问每个月的兔子总数为多少? #通过数学分析我们知道,兔子的规律为数列1, ...

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

    14天阅读挑战赛 神奇的兔子序列 假设第1个月有1对刚诞生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去.那么,由1对初生兔子开始,12个月后会有多少 ...

  7. JavaScript初级玩法(3)—兔子问题(斐波那契数列)

    问题 有人想知道一年内一对兔子可繁殖成多少对,便筑了一道围墙把一对兔子关在里面.已知一对兔子每一个月可以生一对小兔子,但是一对兔子要从出生后第三个月才开始生小兔子假如一年内没有发生死亡,则一对兔子一年 ...

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

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

  9. java递归方法编写兔子繁殖_2018-04-15 斐波那契数列(兔子繁殖数列)

    费波那契数列(兔子繁殖数列) 兔子在出生两个月后,就有繁殖能力,一对成年而有繁殖力的兔子每个月能生出一对小兔子来.假设一年以后所有兔子都不死,那么一对小兔子一年以后可以繁殖多少对兔子? 我们来分析一下 ...

最新文章

  1. RHEL6.3 DNS高级技术二 通过DNS主从区域复制实现DNS View负载均衡和冗余备份
  2. win10 安装microsoft.net framework3.5
  3. Linux上的Shell之FAQ
  4. Java 获取目录的大小
  5. 吴裕雄 python 机器学习——数据预处理过滤式特征选取SelectPercentile模型
  6. python中和操作目录相关的函数包括_python常用的文件目录操作函数
  7. [渝粤教育] 中国地质大学 测量学 复习题
  8. MATLAB遗传算法工具箱的函数及实例
  9. 流媒体:RTMP 协议完全解析
  10. 蓝牙调试工具如何使用_更新:使用此有价值的工具改进您的蓝牙项目
  11. 截止失真放大电路_这些基本放大器的知识,你会了吗?
  12. 科学院计算机研究所谢教授,谢维波
  13. 31.3 Java进阶之lambda方法引用
  14. 职业规划以兴趣为导向,而不是盲目跟风
  15. SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside stri
  16. arcgis 线转面如何保留线的属性?
  17. 从0开始学爬虫6比价工具开发2之图书信息汇总
  18. 好东西要分享,PCB自动生成元件库和封装库的方法
  19. oracle 中 job 是什么,oracle中的job
  20. Lua--基本语法(table表和泛型for)

热门文章

  1. CodeForces 748D Santa Claus and a Palindrome
  2. 基于springboot+vue的便捷网住宿预约系统
  3. 程序正常启动 telnet端口不通问题处理
  4. 学术小技巧:如何使用easyscholar来提高论文查找效率
  5. 2018年总结:你是我最想靠近的温柔
  6. 汇编学习教程:走进 bp
  7. vue 3 项目实战一(绘制登录界面)
  8. 牛客网华为机试(持续更新ing)
  9. 漫谈RocksDB(一)简介——家有美女初长成,一朝成名天下知
  10. 如何编写前端设计文档