☮斐波那契数列与动态规划

简介: ☮斐波那契数列与动态规划

一、斐波那契数列


斐波那契数列 又称兔子数列,它有这样的公式: Fn = Fn-1 + Fn-2。换句话说,下一个数字是前两个数字的和。


前两个数是1,然后是2(1+1),3(2+1),5(2+3),813...


现在有一个需求是编写一个函数fib(n)返回第n个斐波那契数。


在编写函数之前,还想让大家了解一下动态规划的知识。


二、动态规划中的自顶向下和自底向上


image.png


图片来自书籍 算法导论 第15章动态规划。


三、两种思想在斐波那契数列数列问题种的体现


1. 自顶向下的思想(递归)


function fib(n){
    if (n <= 1) {
        return n
    }
    return fib(n - 1) + fib(n - 2)
}
// 三目简洁版
function fib(n) {
    return n <= 1 ? n : fib(n - 1) + fib(n - 2)
}
复制代码


很显然使用递归能完成需求,但是n较大时会变得很慢,调用该函数会挂起引擎一段时间,消耗所有CPU资源,测试结果可见下图,小伙伴们自己测试时千万不要将n设置的很大,否则你的该页面可能会崩溃的😅。


image.png


why? 为什么会这么慢?我们简单的画出递归树,就知道是为啥了👻


image.png


图片参考自现代JavaScript教程-递归和堆栈


我们可以清楚的看到 fib(3) 被计算了两次,fib(2) 被计算了三次。总计算量远远超过了 n,这造成仅仅对于计算 n=40 来讲,计算量就是巨量的。n越大,计算量就越大。


我们还可以选择不使用递归的解法👇🏿。


2. 自底向上的思想(循环)


function fib(n) { 
    let a = 1
    let b = 1
    for (let i = 3; i <= n; i++) { 
        let c = a + b
        a = b
        b = c
    } return b
}
// 可视化序列
a  b  c 
1, 1, 2
   a  b  c 
1, 1, 2, 3
      a  b  c 
1, 1, 2, 3, 5
         a  b  c 
1, 1, 2, 3, 5, 8
复制代码


该解法的思想就是动态规划种的自底向上,依次类推,直到我们得到需要的值,这比递归快得多,该解法的时间复杂度为O(n),而递归解法的时间复杂度为O(n^2)


四、总结


虽然递归有时解决问题很容易,但是还是要考虑算法的性能,是否出现过多重复的计算,如果出现过多重复的计算,那么这条路一定不是最正确的解法。


两种方法方法得到的算法具有相同的渐进运行时间,仅有的差异是在某些特殊情况下,自顶向下方法并未真正递归地考察所有可能的子问题。由于没有频繁的递归函数调用的开销,自顶向上的时间复杂性函数通常具有更小的系数。

相关文章
|
2月前
斐波那契数列
【10月更文挑战第19天】斐波那契数列。
36 3
|
6月前
|
算法 C++
【动态规划】斐波那契数列模型(C++)
【动态规划】斐波那契数列模型(C++)
|
3月前
|
Java
01_斐波那契数列
01_斐波那契数列
|
6月前
|
算法
【超直白】算法:斐波那契数列
【超直白】算法:斐波那契数列
【超直白】算法:斐波那契数列
|
6月前
|
算法 Java 测试技术
斐波那契数列的四种实现算法
斐波那契数列的四种实现算法
128 3
|
6月前
|
存储 算法
精益求精——斐波那契数列的logn解法
精益求精——斐波那契数列的logn解法
85 0
(1188:1201:)斐波那契数列
(1188:1201:)斐波那契数列
155 0
|
机器学习/深度学习 开发工具
斐波那契数列的四种实现
在编程教程中提到斐波那契数列,通常都是用来讲解递归函数。当一个关于 N 的问题可以转换为关于 N - k 的同样问题时,它就可以尝试用递归的思路来解决。
斐波那契数列问题
斐波那契数列问题
102 0
下一篇
DataWorks