对于菲波那切数列都不陌生了,不啰嗦题目,直接切入正题。
常规解法,也是第一反应:
递归法
public int fib(int n) {
if(n==0 || n==1){
return n;
}else {
return fib(n-1)+fib(n-2);
}
}
代码少,简洁明了,但是运行效率底下!
动态规划法
public int fib(int n) {
if (n < 2) {
return n;
}
int p = 0, q = 0, r = 1;
for (int i = 2; i <= n; ++i) {
p = q;
q = r;
r = p + q;
}
return r;
}
代码量也不是很大,运行速率远高于递归法!
当 n>1n>1 时,每一项的和都等于前两项的和,因此有如下递推关系:
F(n)=F(n-1)+F(n-2)
由于斐波那契数存在递推关系,因此可以使用动态规划求解,动态规划的状态转移方程即为上述递推关系,边界条件为 F(0) 和 F(1)。
根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n)的实现。由于 F(n)只和 F(n-1)与 F(n-2)有关,因此可以使用「滚动数组思想」把空间复杂度优化成 O(1)。
具体思路:
0 1 1 2 3 5 8 13 21 34 ......
由于 F(n)只和 F(n-1)与 F(n-2)有关,所以,F(n+1)只和 F(n-1)与 F(n)有关;既然如此,就可以利用数组动态移动的思想,即每次把数组的第一位移除,数组后一位赋值给上一位,就实现了滚动数组思想。
放在代码里就是:定义p、q,用来表示F(n-1)与 F(n-2);定义r,用来表示F(n);只需要在标志位加一时,实现p、q、r的重新赋值即可。
有些类似于C语言中的计算数组中全部数据的总和,定义一个变量存储总和sum,把后续的值重新赋给循环中定义的变量用来实现总和计算。