兔子问题---细说斐波那契数列

2023-11-13


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

题目描述已知一对兔子每一个月可以生一对小兔子,而一对兔子出生后.第三个月开始生小兔子假如一年内没有发生死亡,则一对兔子开始,第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 };//将结果矩阵初始为单位阵E

void 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;
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

兔子问题---细说斐波那契数列 的相关文章

  • LeetCode-336.回文对、字典树、字符串翻转

    给定一组唯一的单词 找出所有不同 的索引对 i j 使得列表中的两个单词 words i words j 可拼接成回文串 示例 1 输入 abcd dcba lls s sssll 输出 0 1 1 0 3 2 2 4 解释 可拼接成的回文
  • 【剑指offer】数据结构——字符串

    目录 数据结构 字符串 直接解 剑指offer 05 替换空格 剑指offer 17 打印从1到最大的n位数 剑指offer 20 表示数值的字符串 剑指offer 37 序列化二叉树 剑指offer 50 第一个只出现一次的字符 剑指of
  • Lecture 9

    绪论 这一章节介绍的是divide and conquer multiplication divide的意思是分开 conquer的意思是占据 控制 divide and conquer直译下来就是分开后控制 其实就是分而治之的意思 mul
  • 算法基础——大O表示法

    本期主题 算法的大O表示法 目录 1 什么是大O表示法 2 时间复杂度 2 1 时间复杂度定义 2 2 常见算法的时间复杂度 3 数组与链表对比 1 什么是大O表示法 大O表示法是一种特殊的表示方式 指出了算法的速度 指出了最糟情况下的运行
  • 【Leetcode】61. 旋转链表

    题目描述 给你一个链表的头节点 head 旋转链表 将链表每个节点向右移动 k 个位置 题解 旋转链表 找倒数第k个节点 翻转前后链表 执行用时 0 ms 在所有 Java 提交中击败了100 00 的用户 内存消耗 37 8 MB 在所有
  • 【Leetcode】257. 二叉树的所有路径

    题目描述 题解 能用String解决的最好不要走StringBuilder 递归时注意空结点 null 回退和叶子结点判定回退 执行用时 9 ms 在所有 Java 提交中击败了30 66 的用户 内存消耗 39 1 MB 在所有 Java
  • 散列表习题

    1 考虑key的集合S 0 8 16 24 32 40 48 56 64 用除余法构造的散列函数 h1 key key 12 h2 key key 11 h1将S映射到的值域有几个元素 3 h2将S映射到的值域有几个元素 9 2 散列表的规
  • 可加密解密的MD5算法

    public class MD5andKL MD5加码 32位 public static String MD5 String inStr MessageDigest md5 null try md5 MessageDigest getIn
  • c语言--输出斐波那契数列的前10个数

    输出斐波那契数列的前10个数 include
  • 单链表的增删改查操作详解之C语言版

    单链表在应用中经常用到增加新结点 删除结点 修改结点 查找结点等操作 本文针对上述基本操作做了简单汇总 并给出了详细的算法 一 在单链表中增加结点 在链表中增加新结点是经常要用到的操作 增加新结点大致可以分为在链表末尾增加 在链表头增加 在
  • LeetCode-剑指 Offer II 114. 外星文字典,BFS 搜索算法及图的表示

    剑指 Offer II 114 外星文字典 现有一种使用英语字母的外星文语言 这门语言的字母顺序与英语顺序不同 给定一个字符串列表 words 作为这门语言的词典 words 中的字符串已经 按这门新语言的字母顺序进行了排序 请你根据该词典
  • vscode——debugger

    提示 本文适用于vscode编译java代码调试初学者 文章目录 debugger图标介绍 左侧工具栏 调试代码 debugger图标介绍 在进行调试之前我们应先在代码前打断点 调试程序时 代码就会运行至断点位置然后停下 断点即为行数前小红
  • 【Leetcode】154. 寻找旋转排序数组中的最小值 II

    题目描述 已知一个长度为 n 的数组 预先按照升序排列 经由 1 到 n 次 旋转 后 得到输入数组 例如 原数组 nums 0 1 4 4 5 6 7 在变化后可能得到 若旋转 4 次 则可以得到 4 5 6 7 0 1 4 若旋转 7
  • 算法训练day43

    文章目录 1049 最后一块石头的重量 II 求最大重量 思路分析 代码实现 494 目标和 求组合方法数 思路分析 动规方法 代码实现 总结思考 474 一和零 求二维背包的最大物品数 思路分析 代码实现 思考总结 1049 最后一块石头
  • 【Leetcode】225. 用队列实现栈

    题目描述 请你仅使用两个队列实现一个后入先出 LIFO 的栈 并支持普通栈的全部四种操作 push top pop 和 empty 实现 MyStack 类 void push int x 将元素 x 压入栈顶 int pop 移除并返回栈
  • 算法:2-3平衡树与B树的详细探讨

    2 3树是最简单的B树 B 树是B树的升级 B树的来源 为什么要有树 描述 1 多 N M 层次等关系 从最根本的原因来看 使用树结构是为了提升整体的效率 插入 删除 查找 索引 尤其是索引操作 因为相比于链表 一个平衡树的索引时间复杂度是
  • 实现 strStr() 函数

    实现 strStr 函数 给定一个 haystack 字符串和一个 needle 字符串 在 haystack 字符串中找出 needle 字符串出现的第一个位置 从0开始 如果不存在 则返回 1 示例 1 输入 haystack hell
  • 设计模式(四) —— 观察者模式/发布订阅模式,c和c++示例代码

    往期地址 设计模式 一 简单工厂模式 设计模式 二 策略模式 设计模式 三 装饰模式 本期主题 使用c和c 代码 讲解观察者模式 发布订阅模式 发布 订阅模式 1 什么是发布 订阅模式 2 实例 2 1 场景 2 2 代码设计 2 3 代码
  • 数据结构系列——链表linklist

    本期主题 数据结构之 链表 往期链接 数据结构系列 先进先出队列queue 数据结构系列 栈 stack 目录 1 链表定义 2 代码实现链表 1 链表定义 定义 链表由多个结点组成 结点不仅包含值 还包含到下一个结点的信息 所以通过这种方
  • 【数据结构】KMP算法

    算法简介 传统暴力算法和KMP算法 设定主串的长度为n 字串的的长度为m 传统的暴力字符串匹配算法理论上最多需要花费O nm 的时间复杂度才能完成串的匹配操作 但是在实际使用中 往往也能够以接近O m n 的时间复杂的完成匹配操作 因此现在

随机推荐

  • 【华为OD】

    目录 一 题目描述 二 输入描述 三 输出描述 用例 四 题目解析 五 Java玩法 六 JavaScript玩法 一 题目描述 某云短信厂商 为庆祝国庆 推出充值优惠活动 现在给出客户预算 和优惠售价序列 求最多可获得的短信总条数 二 输
  • 2021年江苏省职业院校技能大赛中职 网络信息安全赛项试卷--web安全渗透测试解析

    2021年江苏省职业院校技能大赛中职 网络信息安全赛项web安全渗透测试 2021年江苏省web安全渗透测试任务书 2021年江苏省web安全渗透测试任务书解析 如果有不懂得地方可以私信博主 欢迎交流 需要环境得 可以加博主联系方式 202
  • Ansible学习笔记2

    Ansible是Python开发的自动化运维工具 集合了众多运维工具 Puppet cfengine chef func fabric 的优点 实现了批量系统配置 批量程序部署 批量运行命令等功能 特点 1 部署简单 2 默认使用ssh进行
  • idea的代码文本距离左边很远问题解决

    idea的代码文本距离左边很远问题解决 刚才看了篇文章 是关于idea 2021 1版本 看起来挺好 然后忍不住尝试了一下 但是不知道做了什么操作 突然代码的左边距离行号非常远 然后找了很多文章 也没找到解决办法 重新安装idea仍旧没解决
  • springboot2.0集成ShardingSphere-jdbc5.0-alpha所遇到的一些坑

    在springboot 2 5 3中配置使用ShardingSphere 5 0 alpha遇到了不少的坑 现在总结如下 1 没有使用shardingsphere jdbc core spring boot starter 在使用Shard
  • centos下安装apache

    下载所需要的包 wget http mirrors tuna tsinghua edu cn apache httpd httpd 2 4 54 tar gz wget http mirrors tuna tsinghua edu cn a
  • GnuTLS recv error (-110): The TLS connection was non-properly terminated问题的解决方案

    我在使用git clone branch 3 4 depth 1 https github com opencv opencv git命令的时候 遇到如下问题 fatal unable to access https github com
  • Radware负载均衡项目配置实战解析之一初识RADWARE(VIP与FARM配置)

    在近期的项目中 接触负载均衡设备RADWARE比较多 可能有很多朋友对这个设备还不是很了解 所以我把具体项目实战中的Radware配置应用与大家做一个分享交流 RADWARE是一家智能应用网络解决方案的全球领先供应商 主要生产应用交付和网络
  • Ubuntu下无法打开终端

    在安装某个版本的python并进行一系列自己也看不懂的配置之后 突然发现终端无法打开了 具体来说就是从桌面点击没有用 ctrl alt T也打不开 只能从选择文件夹 右击选择终端打开时可以 然后开始救赎之路 打开vscode的终端 或pyc
  • Python开发难学吗?简单易用适合初学者入门

    Python开发难学吗 适合初学者吗 Python入门阶段零基础学员打好基础是非常重要的 在非常高的抽象计算中 高级的Python程序设计非常难学 高级程序语言不等于简单 但对于初学者和完成普通任务Python语言是非常简单易用的 Pyth
  • 四、【服务器】服务器入门——常见单位

    U 高度单位 U 是UNIT的缩写 1U 4 445cm 是一种表示机架服务器外部尺寸的单位 指的是高度或者说厚度 规定这个尺寸是为了使得服务器保持适当的尺寸 在机柜安装的时候需要注意到留好安装高度 机架服务器通常宽度在19英寸 高度为1U
  • 小波分析

    本文首先介绍了从傅里叶变换到小波变换的发展史 然后着重强调了小波变换的两种作用 时频分析和多分辨率分析 最后讲了一下吉布斯效应等相关知识 FT 傅里叶变换 通过将信号分解成正余弦函数 把三角函数当做函数空间的基 将时域信号转化为频域信号 缺
  • Ubuntu16.04升级docker ce错误:Depends: libseccomp2 (>= 2.3.0) but 2.2.3-3ubuntu3 is to be installed

    环境 系统 Ubuntu16 04 docker old version Docker version 1 10 3 build 20f81dd 按照官方给出的步骤安装 https docs docker com install linux
  • DGL-kernel的变更(3)

    导读 DGL kernel中针对Graph的计算几个版本有了不小的变动 v0 3 0 4使用的是minigun v0 3和v0 4源码中主要相关部分则是在对应分支dgl src kernel目录下 v0 5中对kernel代码进行了重写 并
  • IOS学习笔记(十二)之IOS开发之表视图(UITableView)的相关类,属性与表视图实现学习(二)

    iOS学习笔记 十二 之IOS开发之表视图 UITableView 的讲解与使用 二 博客地址 http blog csdn net developer jiangqq 转载请注明地址 Author hmjiangqq Email jian
  • 记录一个问题maven jar 引入

    分模块创建项目jar包无法引入错误 明明在 确保错 无奈最后换个本地仓库地址 重新下载jar 结果不报错了 估计是jar包太多了 混乱导入造成的
  • MySQL中tinyint(1)与tinyint(2)的区别

    一 tinyint类型的介绍 1个tinyint类型的字段占用一个字节 一个int类型的字段占用四个字节 CREATE TABLE user id int 11 NOT NULL COMMENT ID age tinyint 1 NOT N
  • nginx配置SSL协议,80端口443端口。和非80/443端口

    1 80 443 server listen 80 server name www 域名 com rewrite https server name 1 permanent server listen 443 server name www
  • 前端项目查找网站有哪些?面试必看

    教你们一招 项目在这些地方找 面试官眼前一亮 还有一些面试技巧 收藏 工作年限 3 年工作经验 5个项目以上 2 年工作经验项目 4 个项目 技术栈 Vue vuex vue router webpack ES6 node vue reso
  • 兔子问题---细说斐波那契数列

    对于兔子问题的鼎鼎大名 相信很少有人没听过吧 为了完整性还是再说一下题目吧 题目描述 已知一对兔子每一个月可以生一对小兔子 而一对兔子出生后 第三个月开始生小兔子假如一年内没有发生死亡 则一对兔子开始 第N个月后会有多少对 这道题所描述的就