斐波那契数列

一、最基本的

所以,只要知道这个数列的前两项,就可以求出之后所有项了。
核心部分(最简单的递推方法,但是范围是n<=48,否则会超时and溢出):

#include <cstdio> //头文件
int main()
{double f[50];int n, i;f[0] = 0;   //其实并没有用f[1] = 1;f[2] = 1;   //两个初始值scanf_s("%d", &n);for (i = 3; i <= n; i++)f[i] = f[i - 1] + f[i - 2];  //开始使用斐波那契数列printf("%0.2lf", f[n]); //输出,保留两位小数return 0;
}

【注意,这种简单方法还有一种表示,就是用函数写,把递推式变成函数的递归调用,也很好理解。但是亲测会比递推式的时间长很多,n>35的时候就TLA了。因此这提示我们,函数的递归是很耗时的,不要多用。同时上述方法比较快的一个原因是用数组储存时,许多已经算过的数就不用算了,当然会快很多】

二、快速做法(矩阵乘法+快速幂 )

矩阵乘法推导

F i = F i − 1 + F i − 2 F_i = F_{i-1} + F_{i-2} Fi​=Fi−1​+Fi−2​
F i − 1 = F i − 1 + 0 F_{i-1} = F_{i-1} + 0 Fi−1​=Fi−1​+0

把两个式子转化为矩阵形式,即(都是2x2的方便写代码)
{ F i 0 F i − 1 0 } = { 1 1 1 0 } ∗ { F i − 1 0 F i − 2 0 } \left\{\begin{matrix}F_i&0\\F_{i-1}&0\end{matrix}\right\}= \left\{\begin{matrix}1&1\\1&0\end{matrix}\right\}*\left\{\begin{matrix}F_{i-1}&0\\F_{i-2}&0\end{matrix}\right\} {Fi​Fi−1​​00​}={11​10​}∗{Fi−1​Fi−2​​00​}

{ F i − 1 0 F i − 2 0 } = { 1 1 1 0 } ∗ { F i − 2 0 F i − 3 0 } \left\{\begin{matrix}F_{i-1}&0\\F_{i-2}&0\end{matrix}\right\}= \left\{\begin{matrix}1&1\\1&0\end{matrix}\right\}*\left\{\begin{matrix}F_{i-2}&0\\F_{i-3}&0\end{matrix}\right\} {Fi−1​Fi−2​​00​}={11​10​}∗{Fi−2​Fi−3​​00​}
…一直到

{ F 3 0 F 2 0 } = { 1 1 1 0 } ∗ { F 2 0 F 1 0 } \left\{\begin{matrix}F_3&0\\F_{2}&0\end{matrix}\right\}= \left\{\begin{matrix}1&1\\1&0\end{matrix}\right\}*\left\{\begin{matrix}F_{2}&0\\F_{1}&0\end{matrix}\right\} {F3​F2​​00​}={11​10​}∗{F2​F1​​00​}

总结即
{ F i 0 F i − 1 0 } = { 1 1 1 0 } ( i − 2 ) ∗ { F 2 0 F 1 0 } \left\{\begin{matrix}F_i&0\\F_{i-1}&0\end{matrix}\right\}= \left\{\begin{matrix}1&1\\1&0\end{matrix}\right\}^{(i-2)}*\left\{\begin{matrix}F_{2}&0\\F_{1}&0\end{matrix}\right\} {Fi​Fi−1​​00​}={11​10​}(i−2)∗{F2​F1​​00​}


{ F i 0 F i − 1 0 } = { 1 1 1 0 } ( i − 2 ) ∗ { 1 0 1 0 } \left\{\begin{matrix}F_i&0\\F_{i-1}&0\end{matrix}\right\}= \left\{\begin{matrix}1&1\\1&0\end{matrix}\right\}^{(i-2)}*\left\{\begin{matrix}1&0\\1&0\end{matrix}\right\} {Fi​Fi−1​​00​}={11​10​}(i−2)∗{11​00​}

基于此方法,可以看到我们要求的就是一个矩阵的i-2次幂即可,然后 F i F_i Fi​就等于结果再乘以一个[1 0 ,1 0] 的第 [0][0] 个元素。

而求幂,我们可以采用快速幂的方法:

快速幂

快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。

戳下面链接理解快速幂原理:
快速幂算法 刘杨俊

//base为底数,power为指数,求结果的后三位(求后三位就对结果对1000取模即可)
#include<iostream>
using namespace std;long long fastPower(long long base, long long power)
{long long result = 1;while (power > 0) {if (power % 2 == 1)//如果指数为奇数result = result * base % 1000;//相当于结果里已经乘过一次被分离出来的底数了power = power / 2;    //不管对于奇数/偶数,除以2就是整数base = base * base % 1000;    //指数除2,则底数平方cout << "base:" << base << "power:" << power << endl;}
return result;
}int main() {int base, power;cin >> base >> power;cout << fastPower(base, power);return 0;
}

运行结果:

矩阵快速幂

首先矩阵乘法的模板长这样,还是很好理解的:

int main()
{int a[110][110] = {};int b[110][110] = {};int c[110][110] = {};int n = 0, m = 0, p = 0;cin >> n >> m;//矩阵a为n*m(n行m列) for (int i = 0; i < n; i++)    //一行一行地输入for (int j = 0; j < m; j++)scanf("%d", &a[i][j]);cin >> p;  //矩阵b为m*p(m行p列)for (int i = 0; i < m; i++)for (int j = 0; j < p; j++)scanf("%d", &b[i][j]);//重点在这里for (int i = 0; i < n; i++)   //矩阵c是a与b相乘得到的 for (int j = 0; j < p; j++) //n*p(n行p列) for (int k = 0; k < m; k++)c[i][j] += a[i][k] * b[k][j];    //注意是求多项的和,是+=for (int i = 0; i < n; i++){for (int j = 0; j < p; j++)cout << c[i][j] << " ";cout << endl;}return 0;
}

矩阵快速幂即对矩阵使用快速幂的思想,既然求幂了就说明这是个方阵,设为NxN,对于方阵的乘法就要简洁很多:

#include <bits/stdc++.h>using namespace std;struct Matrix {long long a[N][N];
};   //定义一个结构,方便作为返回值,并且进行重载运算符,不然要写很多次函数hhhMatrix operator * (Matrix a, Matrix b) {   //重载对Matrix类型变量的运算符*(乘号),就是写的一个乘法,a和b都是NxN的方阵Matrix ans;memset(ans.a, 0, sizeof(ans.a));   //初始化为0for (int i = 0; i < N; i++)for (int j = 0; j < N; j++)for (int k = 0; k < N; k++)ans.a[i][j] += a.a[i][k] * b.a[k][j];return ans;
}

矩阵快速幂:把快速幂的思想应用于矩阵的方阵乘法【这里就是快速幂的核心了,和前面实数是一样的,如果指数是奇数则把底数y取出来,如果是偶数就使底数平方,指数-1…】

Matrix power(Matrix a, int p) {    //对a求p次幂的函数Matrix y = a, k = a;   //y是一个中间变量,k是结果int t = p;while (t) {if (t & 1) k = k * y;   //t&1,若t为奇数,则结果为1!y = y * y;t >>= 1;   //t-1的高端写法!}return k;
}

完整代码

把矩阵快速幂应用于斐波那契数列:
{ F i 0 F i − 1 0 } = { 1 1 1 0 } ( i − 2 ) ∗ { 1 0 1 0 } \left\{\begin{matrix}F_i&0\\F_{i-1}&0\end{matrix}\right\}= \left\{\begin{matrix}1&1\\1&0\end{matrix}\right\}^{(i-2)}*\left\{\begin{matrix}1&0\\1&0\end{matrix}\right\} {Fi​Fi−1​​00​}={11​10​}(i−2)∗{11​00​}
就是,当求Fn的时候,只要求[1 1 ,1 0]的n-2次幂乘以[1 0 , 1 0]:

//所有数字的定义一定要记得是long long......血的教训#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;const int N = 3;
const long long mod = 1000000007;   //一般结果都很大!要取模struct Matrix {long long out[N][N];
};   //定义一个结构,方便作为返回值,并且进行重载运算符,不然要写很多次函数hhhMatrix operator * (Matrix a, Matrix b) {//重载对Matrix类型变量的运算符*(乘号),就是写的一个乘法,a和b都是NxN的方阵Matrix ans;memset(ans.out, 0, sizeof(ans.out));   //初始化为0for (int i = 1; i < N; i++)for (int j = 1; j < N; j++)for (int k = 1; k < N; k++)ans.out[i][j] = ans.out[i][j] + (a.out[i][k] * b.out[k][j]) % mod;return ans;
}Matrix power(long long p) {    //对底数求p次幂的函数Matrix base;base.out[1][1] = 1;base.out[1][2] = 1;base.out[2][1] = 1;base.out[2][2] = 0;Matrix ans;ans.out[1][1] = 1;ans.out[1][2] = 0;ans.out[2][1] = 0;ans.out[2][2] = 1;long long t = p;while (t > 0) {if (t & 1)   //t&1,若t为奇数,则结果为1!{Matrix tmp = ans * base;for (int i = 1; i < N; i++)for (int j = 1; j < N; j++)ans.out[i][j] = tmp.out[i][j];}Matrix tmp = base * base;for (int i = 1; i < N; i++)for (int j = 1; j < N; j++)base.out[i][j] = tmp.out[i][j];t >>= 1;   //t-1的高端写法!}return ans;
}int main() {long long n;cin >> n;n = n - 2;if (n == 1 || n == 2){cout << 1;return 0;}Matrix result = power(n);long long feib = (result.out[1][1]+result.out[1][2]) % mod;printf("%lld\n", feib);return 0;
}

三、理论表达式

有这么一道题目很有意思的题:



如果不熟悉斐波那契数列可能还需要花费一些时间…所以在这里把这一点列出来,只要看出了这道题的本质就是求斐波那契数列,就非常的简单了。


(摘自洛谷 密期望的题解)


算法学习笔记五 斐波那契数列相关推荐

  1. java学习笔记之斐波那契数列

    斐波那契数列计算公式为: f(n) = f(n-1)+ f(n-2) 基于此写了一个方法,用于输出一个长度为指定的斐波那契数列(从正数1开始, 即1,1 ,2 ,3 ,5 ....): static ...

  2. 经典算法(6)斐波拉契数列、兔子繁殖、跳台阶算法

    写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字.我热爱技术.热爱开源.热爱编程.技术是开源的.知识是共享的. 这博客是对自己学习的一点点总结及记录,如果您对 Java.算法 感兴 ...

  3. 初学算法——第二天:斐波那契数列

    14天阅读挑战赛 1 定义 斐波那契数列的定义者,是意大利数学家莱昂纳多·斐波那契(Leonardo Fibonacci),生于公元1170年,卒于1250年,籍贯是比萨.他被人称作"比萨的 ...

  4. 算法优化:探索斐波那契数列的新航线

    只有用水将心上的雾气淘洗干净,荣光才会照亮最初的梦想. --加西亚·马尔克斯 最近沉迷于算法,总是想着实现与优化,今天想到了斐波那契数列,原来没咋多想,现在回头再看看能不能输出点新花样?! 什么是斐波 ...

  5. 算法(1)斐波那契数列

    1.0 问题描述 实现斐波那契数列,求第N项的值 2.0 问题分析 斐波那契数列最简单的方法是使用递归,递归和查表法同时使用,可以降低复杂度. 根据数列特点,同时进行计算的数值其实只有3个,所以可以使 ...

  6. 427-动态规划算法-斐波那契数列

    动态规划算法求解斐波那契数列 状态:dp数组,存储已经求解的子问题的最优解 递归版本的动态规划算法 //参数n表示斐波那契数列中数字的个数. //返回相应个数的斐波那契数列数字的值. int fabn ...

  7. 数学之美|斐波那契数列与黄金分割

    14天阅读挑战赛 系列文章目录 趣味算法(第二版)读书笔记: day1: 序章|学习的方法和目标. day2:算法之美|打开算法之门与算法复杂性 day3.算法之美|指数型函数对算法的影响实际应用 d ...

  8. 斐波那契数列递归与非递归精讲

    斐波那契数列是学习算法的入门级算法,要对算法进行研究的话我们就必须的掌握斐波那契数列算法.以下从斐波那契数列的简介,递归算法和非递归算法给大家进行介绍.   简介: 斐波那契数列(Fibonacci ...

  9. JS实现给定参数数范围内的有条件求和(以质数求和与斐波那契数列求和为例)

    文章目录 前言 一.应用场景 二.算法举例 1. 求斐波那契数列中的奇数之和 2. 质数求和 总结 前言 本文给出一种JavaScript算法,用以实现给定参数数范围内的有条件求和.并以求斐波那契数列 ...

最新文章

  1. android多音字排序,Android拼音排序
  2. 关于HTML5中Canvas的宽、高设置问题
  3. 发现 ASP.Net 的一个关于回车提交的 Bug ? 必须多于一个 Text 域回车提交,Server: ButtonX_Click 才能截获!...
  4. Windows上的Java线程CPU分析
  5. sql 联合查询_一张图看懂sql运行顺序
  6. Portal-Basic Java Web 应用开发框架:应用篇(八) —— 整合 Freemarker
  7. SQL Server 的存储过程[转]
  8. git太慢时的加速办法,测试有效
  9. 西门子博途v14 SP1 S7-1200之间的以太网双边通讯(两个S7-1200 在一个项目中)
  10. 变压器次级输出为0v的原因_加速tensorflow中的Google临时融合变压器2 0
  11. 套接字Socket的常见面试题及答案
  12. Vue-element-admin 基础模板
  13. 详解浏览器中的粘贴事件 paste onpaste 事件
  14. SAP中税码、税率、税务科目的几个表及其中的勾稽关系
  15. 转-零死角玩转stm32-高级篇之SDIO(4bit + DMA、支持SDHC、带协议分析)
  16. 怎样促进计算机专业发展,【计算机教学论文】怎样促进计算机技术应用及改善(共4879字)...
  17. android gpu 视频编码,Android Mp4视频录制(OpenGL实现篇,附DEMO)
  18. R语言独立性检验-基础
  19. u-boot启动流程简图 --木草山人
  20. 【LLYD】That 70s show: why the disco decade is back in fashion

热门文章

  1. JSONArray遍历
  2. 关于函数泰勒展开的关键知识点深入分析
  3. linux服务器执行xshot,【Funtouch OS玩机宝典】:工程模式恢复模式入门指南
  4. P2128 赤壁之战 AC于2018.11.6
  5. 融资约束指数(KZ、SA、FC、WW)(2000-2021年)
  6. SAP中物料主数据锁定字段的功能测试
  7. 解决outlook 2013搜索卡住(不停止)的问题
  8. 中国制造业经济继续处于增长周期 未来还需观察
  9. 从BAT代币抢购说说gas,gasprice
  10. dd-wrt的漫游方式