算法之路(三)----查找斐波纳契数列中第 N 个数
算法题目
查找斐波纳契数列中第 N 个数。
所谓的斐波纳契数列是指:
* 前2个数是 0 和 1 。
* 第 i 个数是第 i-1 个数和第i-2 个数的和。斐波纳契数列的前10个数字是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34 …
分析
斐波那契数列满足公式f(n) = f(n-1) + f(n-2),n > 0。这里我们的第一想法是使用递归,可是直接翻译公式出来的递归调用是这样的:
int fib(int n) {
if (n == 1) {
return 0;
}
if (n == 2){
return 1;
}
return fib(n - 1) + fib(n - 2);
}
可是这个函数的事件复杂度恰好是最糟糕的指数级。怎么来证明它是指数级呢?
你可以先用一些测试数来测试一下这个方法:
当n = 40时,大概就需要0.5秒才能计算出来;
当n 为50时,需要等很久才能计算出实际的值。
下面来推导它的时间复杂度。
对于斐波那契数,有定理 :当n >= 0时,Fn < (5/3)n。
首先使用归纳法来证明。对于基准情形,F1 = 0 < 5/3,F2 = 1 < 5/3。
然后假设i = 1,2,3,…,n 成立;这就是归纳假设。那么我们只需要证明出Fn+1 < (5/3)n+1 即可。
根据公式我们可以得出Fn+1 = Fn + Fn-1。
推到过程如下:
Fn+1 < (5/3)n + (5/3)n-1
Fn+1 < (3/5)(5/3)n+1 + (3/5)2(5/3)n+1
Fn+1 < (24/25)(5/3)n+1 < (5/3)n+1
得证 Fn+1 < (5/3)n+1。
同样的证明过程,可以证明出当n > 4时, Fn > (3/2)n。
而T(n) = T(n-1) + T(n-2) + 3。
T(n) >= fib(n) >= (3/2)n。
因此这个函数的运行时间是以指数的速度增长。
可能有点不同的是,有的斐波那契数列是从1,1,2,3,…. 开始,所以有些微的差别。
这只是对级数做了一次平移。我们可以找一些方便证明的情况来证明。
更优解法
其实上面的递归违反了递归的合成效益法则,才导致了运行时间的指数级增长。
递归的四条基本准则:
1、基准情形。必须有总有某些基准情形,它无须递归就能解出。
2、不断推进。对于那些需要递归求解的情形,每一次递归调用都必须要使求解状况朝接近基准情形的方向推进。
3、设计法则。假设所有的递归调用都能运行。
4、合成效益法则。在求解一个问题的同一示例时,切勿在不同的递归调用中做重复性的工作。
我们可以利用一个简单的for 循环来求解第N个斐波那契数。
int fibonacci(int n) {
if (n == 1) {
return 0;
}
if (n == 2) {
return 1;
}
int a = 0;
int b = 1;
int c = 0;
for (int i = 3; i < n + 1; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
使用两个变量分别保存f(n-1) 和f (n-2),然后从基准情况开始往第 n 个数推进。
改进后的函数时间复杂度是O(n),运行时间大概是 (3n - 1)大大减少了运行时间。
算法之路(三)----查找斐波纳契数列中第 N 个数的更多相关文章
- Java算法求最大最小值,冒泡排序,斐波纳契数列一些经典算法<不断更新中>
清明在家,无聊,把一些经典的算法总结了一下. 一.求最大,最小值 Scanner input=new Scanner(System.in); int[] a={21,31,4,2,766,345,2, ...
- lintcode:Fibonacci 斐波纳契数列
题目: 斐波纳契数列 查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是: 0, ...
- LintCode 斐波纳契数列
查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是: 0, 1, 1, 2, 3 ...
- Java算法求最大最小值,倒序,冒泡排序,斐波纳契数列,日历一些经典算法
一,求最大,最小值 int[] a={21,31,4,2,766,345,2,34}; //这里防止数组中有负数,所以初始化的时候给的数组中的第一个数. int max=a[0]; int min=a ...
- java斐波纳契数列
//斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.-- 这个数列从第三项开始,每一项都等于前两项之和. public class DiGui { public ...
- HDU 4639 Hehe(字符串处理,斐波纳契数列,找规律)
题目 //每次for循环的时候总是会忘记最后一段,真是白痴.... //连续的he的个数 种数 //0 1 //1 1 //2 2 //3 3 //4 5 //5 8 //…… …… //斐波纳契数列 ...
- 用PHP迭代器来实现一个斐波纳契数列(转)
斐波纳契数列通常做法是用递归实现,当然还有其它的方法.这里现学现卖,用PHP的迭代器来实现一个斐波纳契数列,几乎没有什么难度,只是把类里的next()方法重写了一次.注释已经写到代码中,也是相当好理解 ...
- 10、end关键字和Fibonacci series: 斐波纳契数列
# Fibonacci series: 斐波纳契数列 # 两个元素的总和确定了下一个数 a, b = 0, 1 #复合赋值表达式,a,b同时赋值0和1 while b < 10: print(b ...
- HDU 5914 Triangle 斐波纳契数列 && 二进制切金条
HDU5914 题目链接 题意:有n根长度从1到n的木棒,问最少拿走多少根,使得剩下的木棒无论怎样都不能构成三角形. 题解:斐波纳契数列,a+b=c恰好不能构成三角形,暴力就好,推一下也可以. #in ...
随机推荐
- [LeetCode] Find Largest Value in Each Tree Row 找树每行最大的结点值
You need to find the largest value in each row of a binary tree. Example: Input: 1 / \ 3 2 / \ \ 5 3 ...
- pyqt4 写动画不能播放问题集合
最近在学习动画,真的真的是血泪史,百度基本是0资源,各种在谷歌外国大佬的英文中躺过一个一个血坑....... 这是随便写的一个动画功能调试窗口..... 问题现象: 点击食灵,没反应,写的动画不能生成 ...
- 【Swfit】Swift与OC两种语法写单例的区别
Swift与OC两种语法写单例的区别 例如写一个NetworkTools的单例 (1)OC写单例 + (instancetype)sharedNetworkTools { static id inst ...
- [Luogu 2090]数字对
Description 对于一个数字对(a, b),我们可以通过一次操作将其变为新数字对(a+b, b)或(a, a+b). 给定一正整数n,问最少需要多少次操作可将数字对(1, 1)变为一个数字对, ...
- [SDOI2009]虔诚的墓主人
题目描述 小W是一片新造公墓的管理人.公墓可以看成一块N×M的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地. 当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地. ...
- codeforces 651C Watchmen
Watchmen are in a danger and Doctor Manhattan together with his friend Daniel Dreiberg should warn t ...
- [ZJOI2006]超级麻将
题目描述 很多人都知道玩麻将,当然也有人不知道,呵呵,不要紧,我在这里简要地介绍一下麻将规则: 普通麻将有砣.索.万三种类型的牌,每种牌有1~9个数字,其中相同的牌每个有四张,例如1砣~9砣,1索~9 ...
- 洛谷mNOIP模拟赛Day1-分组
传送门 首先是贪心的思路 从后向前选,能多选就多选, 理由:数字越少肯定越优,同时间隔尽量向前推,字典序尽量小 对于K==1,枚举1~512直接判断 对于K==2,需要用镜像并查集,来刻画" ...
- 【Codeforces 851D Arpa and a list of numbers】
Arpa的数列要根据GCD变成好数列. ·英文题,述大意: 给出一个长度为n(n<=5000000)的序列,其中的元素a[i]<=106,然后输入两个数x,y(x,y<=1 ...
- 例10-4 uva10791(唯一分解)
题意:求最小公倍数为n的数的和的最小值. 如12:(3,4),(2,6),(1,12)最小为7 要想a1,a2,a3……an的和最小,要保证他们两两互质,只要存在不互质的两个数,就一定可以近一步优化 ...