編程之美2.9:神奇的菲波那契數列

2024-09-01 05:32

本文主要是介绍編程之美2.9:神奇的菲波那契數列,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

只要是聽說過遞歸,學過一點數據結構的人都聽過這個數列。其實高二數學課上也有,不過那時候我還在受馬克思主義的薰陶,不知編程爲何物。好了,據說這個數列源於一對繁殖能力特別驚人的兔子。
其實這個就是一個遞推公式:

F(n)=01F(n1)+F(n2)n = 0;n = 1;n>=2

一般學校都是在將遞歸時用這個當例子,這當然好。面試提也會考到這道題,Facebook有次就靠到了。不過你要是幹用遞歸寫,你也不用進行下一輪面試了。原因只有一個,太慢!!!重複計算太多!!
你看,如果要求F(5),則計算F(4)和F(3),計算F(4)呢,又要再次計算一下F(3),當然慢。而且函數調用還要保存棧指針,傳遞參數等。
比較好一點的人可能想到用個一維數組。這樣就可以把複雜度降低到 O(n) 了,我也在這裏獻醜了。寫一個我的實現。

滚动数组法

#include <stdio.h>
int arr[3]={0,1};
int main(void){int index=0;printf("Enter the index:\n");scanf("%d",&index);if(index<=2){printf("%d\n",arr[index-1]);return 0;}else{for(int i=3;i<=index;++i){arr[2]=arr[1]+arr[0];arr[0]=arr[1];arr[1]=arr[2];}}printf("%d\n",arr[2]);return 0;
}

好了,这就是传说中的複雜度爲 O(N) 的方法,比之前的递归是要好一点了。面试的时候写这个也差不多达到平均水平了。下面还有一种方法,虽然理论上可以。就是求数列的通项公式,不过这个引入了无理数。所以实际上不行。
下面是最暴的,也是比较有水平的方法。复杂度可以达到 O(Log2N) .策略呢,当然是我抄过来的。用矩阵。
因为Fibonacci是二阶递推数列,所以由矩阵相称的公式可得。存在一个2*2的矩阵A。使得 (FnFn1)=(Fn1Fn2)A
求解可得:

A=(1110)

由上面可以推出: (FnFn1)=(Fn1Fn2)A=(Fn2Fn3)A2=....=(F1F0)An1
看到了没,现在只需要能求出 An1 ,然后做一个矩阵乘法就行啦。
所以我们要做的工作就是实现一个矩阵操作的类或者函数。OK,我在装下B,写一个简单实现。

#include <iostream>
#include <cassert>
using namespace std;
const int N=4;
class Martix{
public:unsigned int size;long long int data[N*N];
};
//Multi bewteen martix and martix
Martix  martixMulti(const Martix A,const Martix B,Martix result){assert(A.size==B.size);result.size=A.size;for(int i=0;i<result.size;++i)for(int j=0;j<result.size;++j){result.data[i*result.size+j]=0;for(int k=0;k<result.size;++k)result.data[i*result.size+j]+=A.data[i*A.size+k]*B.data[k*B.size+j];}return result;
}
//Compute the n-1 of exp
Martix martixPow(Martix &A,int index){if(index==0)exit(0);--index; //compute n-1 expMartix IdenMartix;IdenMartix.size=2;IdenMartix.data[0]=1,IdenMartix.data[1]=0;IdenMartix.data[2]=0,IdenMartix.data[3]=1;Martix result=IdenMartix;for(;index;index>>=1){if(index&1)result=martixMulti(result,A,result);A=martixMulti(A,A,A);}return result;
}
int Fib(int n){Martix A;A.size=2;A.data[0]=1,A.data[1]=1;A.data[2]=1,A.data[3]=0;Martix an=martixPow(A,n);return an.data[0];
}
int main(int agrc,char **argv){unsigned int index;cout<<"Input index:";cin>>index;cout<<Fib(index)<<endl;return 0;
}

上述就是一个简单的实现,不过代码有点小问题。哈,你们自己看着办吧。下篇文章估计写大数计算。正好也实在一下,当菲薄那契数列的项数过大时,无法表示的情况。
参考资料:
<编程之美>书籍
编程之美2.9

这篇关于編程之美2.9:神奇的菲波那契數列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1126071

相关文章

Redis 管道的神奇力量

今天我们要来探索一个 Redis 中非常强大且实用的特性——管道(Pipeline)。如果你想让你的 Redis 操作更加高效,那么这篇文章绝对值得一读。 一、Redis 管道是什么 Redis 管道是一种在客户端和服务器之间批量执行命令的技术。它允许客户端将多个命令一次性发送到服务器,而不是逐个发送并等待每个命令的响应。服务器会按照顺序执行这些命令,并将所有命令的响应一次性返回给客户端。

入门篇:神奇的Annotation

涅槃1992 关注 2016.12.25 23:41* 字数 4964 阅读 1059评论 3喜欢 29 前面写了Android 开发:由模块化到组件化(一),很多小伙伴来问怎么没有Demo啊?之所以没有立刻放demo的原因在还有许多技术点没说完. 今天我们就来细细评味Java当中Annotation,也就是我们常说的注解. 本文按照以下顺序进行:元数据->元注解->运行时注解->编译时

一个人就能干一个团队剪辑工作?云微客就是这么神奇

你知道拍摄、剪辑一条视频需要花费多长时间吗?半个小时?还是一个小时呢?如果我想一天发布上百条视频,你觉得可能吗?很显然,仅凭个人是很难办到的,那么就需要借助工具,而云微客AI批量剪辑系统正好可以解决这个难题。 在当下这个短视频风靡的时代,不管是企业还是个人创作者们都需要借助各种工具和系统来提升创作内容的生产效率和传播效果。而云微客AI批量剪辑系统凭借着批量剪辑的功能,为创作者带来了很大的

第四章 感受Mac之美-效率提高从操作快捷键开始

了解和掌握快捷键,可以提高工作效率,作用和意义是不言而喻的。节省不必要的操作时间,让你专注做自己真正重要的事。 比如最简单的复制,粘贴之类的入门快捷键,如果每个操作都需要右键执行去操作的话,那么在电脑上做什么操作都会慢一拍。 我是在入手俩周后,自己摸索之后,基本对系统里面基本的快捷键都有个印象了。 看了这么多的快捷键,一时半会也记不住啊,是不是有点崩溃啊,不过大家也不用担心快捷键的记不住,今

第二章 感受Mac 之美-惊艳从Mac 外设开始,一周后的使用感受

期望已久,同时老婆也是极力推荐说,既然是吃饭的家伙,那么就下点血本投资下自己,原来那台已经满足不了你现在的工作效率了,继续沿用,得不偿失啊。 衡量了一下目前的情况,同时考虑到自己也是一个程序员爸爸了,也有房贷在身,所以去没有选择 16g 内存,512g 的 ssd,15.4 或者新版 16 寸大屏幕的高配,而是选择了比较适合我现阶段的配置的【Apple 2019 款 MacBook Pro 13

第一章 感受mac之美-换一种方式用电脑,开启新历程

感谢关注我的读者一直以来的追随与信任。去年到今年以来大环境都不是很好。裁员,机构优化,工厂倒闭,公司破产,贸易战等消息传来,不少还是身边发生的。今年开年以来更是有病毒横行,天降蝗灾等灾害。愿大家都好好的,同时希望这场战役早早告捷。今天是二月二 ,民间传说龙抬头,祝愿大家从此事业腾飞,从此出人头地。 我在这断更的两年中的一些情况,一直处于闭关的状态,一直在学习与实践。后续再和大家一起分享这俩年

[编程之美] 2.17 字符串循环移位

题目 将字符串向右循环移动 k 位 s = "abcd123" k = 3Return "123abcd" 思路 方法一 翻转法 将子串 s[0:str.length() - k)] 翻转,子串s[str.length() - k,str.length()] 翻转。然后将整个字符翻转可以到最终结果。 eg: 将 abcd123 中的 abcd 和 123 单独翻转,得到 dcba3

[编程之美] 3.1 字符串循环移位包含

题目 s1 = AABCD, s2 = CDAA Return : true 给定两个字符串 s1 和 s2,要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。 思路 以S1 = ABCD 为例,对其循环移位的后果为: ABCD -> BCDA -> CDAB -> DABC -> ABCD S1S1 = ABCDABCD 看出对S1做循环移位所得到的字符串都将是字符串S1S1的

编程之美——寻找最大的K个数

编程之美——寻找最大的K个数 解法一: 我们先假设元素的数量不大,例如在几千个左右,在这种情况下,那我们就排序一下吧。在这里,快速排序或堆排序都是不错的选择,他们的平均时间复杂度都是 O(N * log2N)。然后取出前 K 个,O(K)。 总时间复杂度 O(N * log2N)+ O(K) = O(N * log2N)。 你一定注意到了,当 K=1 时,上面的算法也是

神奇的android广播

最近用了android的广播,个人感觉非常好用: 首先在你要接收的地方注册一个: context.registerReceiver(myReceiver, new IntentFilter("com.shic.action.d")); 然后就是定义注册的这个,在接收到广播后执行的操作: BroadcastReceiver myReceiver = new BroadcastRecei