算法之路(三)----查找斐波纳契数列中第 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 ...
随机推荐
- No Java compiler available
<!-- 添加tomcat支持 --> <dependency> <groupId>org.springframework.boot</groupId> ...
- Java程序优化之替换swtich
关键字switch语句用于多条件判断,功能类似于if-else语句,两者性能也差不多,不能说switch会降低系统性能.在绝大部门情况下,switch语句还是有性能提升空间的. 但是在项目代码中,如果 ...
- 【转】JAVA异常报错大全
算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeAr ...
- js switch判断 三目运算 while 及 属性操作
三 目运算:如var a = 10: var b= 12: c = a>b ?a:b; 若成立执行a否则执行b var isHide = true; 若用if判断语句如下 if(isHide) ...
- Python的基础学习(第二周)
模块初始 sys模块 import sys sys.path #打印环境变量 sys.argv#打印该文件路径 #注意:该文件名字不能跟导入模块名字相同 os模块 import os cmd_res ...
- seacms6.5 注入漏洞1
---恢复内容开始--- 需要开启/data/admin/isapi.txt ,当里面的数值为1时,就可以报错注入 存在漏洞的页面:zyapi.php function cj() { global ...
- 《C++ Primer》学习笔记:3.3.3其他vector操作
<C++ Primer>(第五版)中计算vector对象中的索引这一小节中,举例要求计算各个分数段各有多少个成绩. 代码如下: #include <iostream> #inc ...
- 计蒜客NOIP模拟赛(2) D1T1邻家男孩
凡是一个具有领导力的孩子.现实生活中他特别喜欢玩一个叫做 UNO 的纸牌游戏,他也总是带着其他小朋友一起玩,然后战胜他们.慢慢地,他厌倦了胜利,于是准备发明一种新的双人纸牌游戏. 初始时,每个人手中都 ...
- THUWC逛街记
1/28 这次打算去THUWC划个水,就定了1/29中午的飞机.同校有几个同学去PKUWC,求稳搭今天的飞机.中午时候听说今天飞长沙的飞机全都取消了,明天有没有也不好说( 事实证明29号有飞机:( ) ...
- Codeforces Round#433 简要题解
来自FallDream的博客,未经允许,请勿转载,谢谢. 我的号自从几个月前姿势水平过低疯狂掉分之后就没动过了 突然想上点分 就打了一场Div1 没想到打到了rank5 一发上橙了,可还行. ...