动态规划问题(1)——斐波那契数列

前段时间一直写了几个算法题目,发现有个很牛逼的算法,动态规划,虽然有的解题思路和动态规划很像,可是当时不知道其中的原理和一些通用性,接下来的几天,经过一些栗子一点一点揭开动态规划那神秘的面霜,我也是现学现卖的,若是有那里写错的欢迎给我留言指正。javascript

动态规划有时被称为递归的相反的技术。递归是从顶部开始将问题分解,经过解决全部分解小问题的方式,来解决整个问题。而动态规划这是从底部开始解决问题,将全部小问题解决掉,而后合并成总体的解决方案,从而解决掉整个大问题。递归方式虽然很简洁,可是效率不高,可是不能说递归是很差的,本质上是,命令式语言和面向对象的语言对递归的实现不够完善,由于它们没有将递归做为高级编程特性。java

动态规划方案一般使用一个数组来创建一张表,用于存放被分解成众多子问题的解。当算法执行完毕,最终的解法将会在这个表中找到。算法

今天咱们先从咱们最熟的斐波那契数列数列开始。编程

0, 1, 1, 2, 3, 5, 8, 13, 21, 24, 55, ...

从数列中能够发现从第三个数开始的值是前两个值的和。数组

递归解法
function fib(n){
    if(n < 2){
        return n;
    }else{
        return fib(n - 1) + fib(n - 2);
    }
}
console.log(fib(10));   // 55
动态规划解法
function fibDyn(n){
    var temp = [];
    for(var i = 0; i <= n; i++){
        temp[i] = 0
    }
    if(n == 1 || n == 2){
        return 1;
    }else{
        temp[1] = 1;
        temp[2] = 2; 
        for(var i = 3; i < n; i++){
            temp[i] = temp[i - 1] + temp[i -2];
        }
        return temp[i - 1];
    }
}
fibDyn(10)  // 55

从程序中咱们能够看出,初始化了一个和传入等长的空数组,去存放每次运算厚的结果。微信

测试程序运行时间
var start = new Date().getTime();
console.log(fib(10))
var stop = new Date().getTime();
console.log('递归消耗' + (stop - start) + '毫秒');

start = new Date().getTime();
console.log(fibDyn(10))
stop = new Date().getTime();
console.log('动态规划消耗' + (stop - start) + '毫秒');

运行结果测试

55
递归消耗-- 0 毫秒
55
动态规划消耗-- 0 毫秒

fib(20)优化

6765
递归消耗-- 1 毫秒
6765
动态规划消耗-- 0 毫秒

fib(30)spa

832040
递归消耗-- 17 毫秒
832040
动态规划消耗-- 0 毫秒

改变fib(n)中的 n 的值咱们会发现,动态规划的解决方案姚比递归解决方案高效不少。code

优化斐波那契数列的动态规划算法

咱们看到这个动态规划的算法是要了一个空数组,这是你可能已经想到使用迭代的方案计算,能够不使用数组,须要用到的素组的缘由事由于动态规划算法一般须要吧中间的结果保存起来。一下是优化的迭代版。

function fibDyn(n){
    var prev = 1;
    var middle = 1;
    var result = 1;

    for(var i = 2; i < n; i++){
        result = prev + middle;
        prev = middle;
        middle = result;
    }
    return result;
}
fibDyn(10)  // 55

这时候咱们能够看到少了建立数组这一步,效率没变,可是空间复杂度变小了。

斐波那契数列在不少地方都会用上,我是从一个台阶问题发现的,同时知道了动态规划的解法。有兴趣的能够在公众号中回去“台阶问题”


欢迎关注微信公众帐号查看最新文章

欢迎关注微信公众帐号查看最新文章

相关文章
相关标签/搜索