每周一刷——从斐波那契数列到动态规划

一、写在前面的话

在csdn上看到一篇博客,博客的内容有有关图像方面的paper,有有关机器学习的理论推导和python实践,文风简洁而不拖沓,非常喜欢,仿佛找到了同类,翻到“about me”以及一些求职的博文,方向选择之困惑,在求学期间学习方法之反思(实践、实践、还是实践)。仿佛看到了自己,看到了自己的明天,这位博主对算法之深刻,找工作之路尚感艰难,何况我呢。顿感企业要求之高(基础之看重),算法学习之路艰辛,学习之法之重要。这里,今天,特开一个算法系列,在基于数学的机器学习算法之外,重新整理更为基础的数据结构与算法。绳锯木断水滴石穿,星星之火可以燎原,为以后的求职之路打下基础。

既然是写在前面的话,不妨订立几条标准。

  • 更新的频次上,   2篇/周;

  • 不简单地粘贴代码,必须凝结自己的思考;

  • 透过实现的技巧看算法的本质,通过代码理解基本概念;

  • ……

这个系列主要参考的书有:

二、普通版

首先以递归的形式定义Fibonacci数列的第 N  F(N) 的计算公式:

F(n)={ nn1F(n1)+F(n2)n2  

根据此递归形式的定义,可得出二分递归版fib(n)算法:

// sizeof(__int64) == 8
// sizeof(__int64) == sizeof(long long)
// 注意斐波那契数列的增长速度是很快的,fib(40)的值已超过10^9
__int64 fib(unsigned n)     
{
    if (n <= 1)
        return n;
    else
        return fib(n-1) + fib(n-2);
}

简单的if-else语句又可进一步简化为三目运算符:

__int64 fib(unsigned n)
{
    return (n <= 1) ? __int64(n) : fib(n-1) + fib(n-2);
}

三、改进版

虽然定义、形式和实现上都十分简单和便于理解,二分递归版却存在大量重复计算的问题。以 F(10)  的递归计算为例考察二分递归版的重复计算问题,如图示:


F(10)

解决的思路便是考虑如何利用已计算的中间值来计算当前要计算的值,剑指offer给出的解决方案是,完全不在沿用传统的递归计算(从后向前的)方式,而是采用顺序的循环的向后计算方式,为了方便计算需引入两个中间变量

__int64 fibNMinus1, fibNMinus2;

分别表示 F(n1)  F(n2)  来记录每一次参与循环计算的第一个加数和第二个加数。代码如下:

__int64 fib(unsigned n)
{
    if (n <= 1)
        return n;
    __int64 fibNMinus1 = 1;
    __int64 fibNMinus2 = 0;
    __int64 fibN = 0;
    for (unsigned i = 2; i <= n; ++i)
    {
        fibN = fibNMinus1 + fibNMinus2;
        fibNMinus2 = fibNMinus1;
        fibNMinus1 = fibN;
    }
    return fbN;
}

四、动态规划版

剑指offer提供的替代方案仍然具有一定的技巧性,所谓技巧性也即不可复制性,这里提供一种通用的解决方案,所谓的通用,是因为它利用了一种算法思想:动态规划(DP:dynamic programming),这里抛开动态规划严格且抽象的定义,我们从它的实现方式入手,也即记录结果再利用,我们来看动态规划版本的计算方法:

long long memo[N+1];        // 全局变量,初始化为0
long long fib(unsigned n)
{
    if (n <= 1)
        return n;
    if (memo[n]) return memo[n];
    else
        return memo[n] = fib(n-1) + fib(n-2);
}

这里看似好像仍然是之前的递归形式相同,然而,通过查看其递归调用的流程可以发现,分支的右侧,已在左侧计算出且保存在mem[n]中,


这里写图片描述

这篇博客的最终目的是为了引出动态规划的算法思想,自然想要把握动态规划的精髓,是完全不够的,会在以后的文章中反复思考和探索动态规划。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值