美文网首页
关于动态规划的一点探究

关于动态规划的一点探究

作者: 袁方 | 来源:发表于2019-10-20 17:48 被阅读0次

概念

一般来说, 我们需要解决的问题大多数都较为直接, 可以用一种方法或思路直接了当的完成. 然而在开发过程中, 会遇到些许无法一次性解决的的复杂问题. 此时我们就需要把复杂问题分解为若干个小问题, 再 step by step 地解决小问题, 从而去得出该复杂问题的最终解. 这就叫做"动态规划".

场景

已知斐波那契数列的第n项是第n - 1项与第n - 2项的的和, 该数列的前两项都是1, 求斐波那契数列的的第100项

最直接的想法是用循环的方式相加98次即可, 那么用动态规划应该怎么写呢?一般来说, 动态规划分为两步:
1)初始状态, 即此问题的最简单子问题的解. 在斐波那契数列中, 最简单子问题自然是第一项和第二项的值, 解均为1.
2)状态转移方程, 即第n个问题的解和之前的 n - m 个问题解的关系. 在斐波那契数列中, 我们已经有了状态转移方程 F(n) = F(n - 1) + F(n - 2).

所以要知道F(100), 我们计算出F(99)与F(98)相加即可; 知道F(99), 我们计算出F(98)与F(97)相加即可; 以此类推...最后, 我们不难得出只要知道F(2)和F(1)的值, 就可以计算出F(100). 而F(2)和F(1)正是初始状态, 均为1, 所以可以写出代码:

static func Fibonacci(_ index: Int) -> Int {
  // * 定义初始状态
  guard index > 0 else {
    return 0
    
  }
    
  if index == 1 || index == 2 {
    return 1
    
  }

  // * 调用状态转移方程
  return Fibonacci(index - 1) + Fibonacci(index - 2)
    
} 

警告⚠️

这种写法看起来简洁明了, 但存在一个问题: 存在大量的重复计算. 比如要计算F(100), 需要计算出F(99)与F(98); 要计算F(99), 需要计算出F(98)与F(97); 此时F(98)已经被计算了两次, 以此类推...不难发现这种写法的浪费了很多时间. 我们也很容易想到用一个数据模型记录下已经计算出的F(n), 牺牲空间来换取提高效率. 笔者使用的是字典, key为项数(n), value为值(F(n)). 代码如下:

static var recordDict: [Int: Int] = [
        0: 0,
        1: 1
] // * 此处虚构了一个值为0的第0项

static func sequenceFibonacci(_ index: Int) -> Int {

    if recordDict[index] == nil {
        
        let result = self.sequenceFibonacci(index - 2) + self.sequenceFibonacci(index - 1)
        
        recordDict[index] = result
        
    }
    
    return recordDict[index]!
    
}

虽然看上去高大上,但在实际应用中一定注意以下两点:

1)内存溢出:每一次递归, 程序都会将当前的计算结果写入内存中. 随着递归愈来愈深, 所占内存也愈来愈大. 若超过系统分配给当前进程的内存容量, App就会Crash.
2)数据溢出:动态规划是一种由简至繁的过程, 其中累积的计算结果有可能超过当前数据类型的最大值, 从而导致程序抛出异常.

我们在上面的场景中会遇到第二点. 程序会在计算到F(93)时因为Int型数据溢出Crash. 在Swift中, Int 类型只能表示介于 -9,223,372,036,854,775,808 到 +9,223,372,036,854,775,807的数. 而F(92)的结果已经是7,540,113,804,746,346,429, 所以F(93)一定超过了Int 类型所能表示的最大值.

当然我们也有相应的方法去避免这两个问题.
1)对付内存溢出, 我们可以把递归写成循环的形式来避免.
2)对付数据溢出, 我们可以在每次计算时加入数据溢出的检测, 及时抛出异常并结束计算.

相关文章

  • 关于动态规划的一点探究

    概念 一般来说, 我们需要解决的问题大多数都较为直接, 可以用一种方法或思路直接了当的完成. 然而在开发过程中, ...

  • Dynamic Programming(动态规划)类算法分析随笔

    #动态规划 关于动态规划,先摘一段[wiki][1]的描述: ``` 动态规划(英语:Dynamic progra...

  • 关于动态规划

    最长公共子序列 问题描述: 解题方法: 参考: http://blog.csdn.net/hrn1216/arti...

  • 关于动态规划

    (一)打家劫舍问题 1.打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯...

  • 2018-11-14

    今天学了动态规划一些知识,着重看了一下动态规划之背包算法(主要是0-1算法和部分算法),关于动态规划的问题重点是建...

  • Algorithm进阶计划 -- 动态规划(上)

    动态规划动态规划的基本原理动态规划的运用 1. 动态规划的基本原理 动态规划(Dynamic Programmi...

  • 动态规划 Dynamic Programming

    从运筹学和算法的角度综合介绍动态规划 算法分类总结动态规划与静态规划的关系浅析静态规划和动态规划动态规划解非线性规...

  • 算法3:动态规划

    5.动态规划5.1 什么是动态规划?5.2 自底向上的动态规划:5.3 自顶向下的动态规划5.4 0-1背包问题:...

  • 4. 动态规划算法

    1. 动态规划算法总结2. 漫画:什么是动态规划?3.算法之动态规划4. 动态规划-算法

  • 什么是动态规划

    目录 动态规划解决了什么 什么是动态规划 典型的动态规划 1. 动态规划解决了什么 的思想就是将大问题拆分成小问题...

网友评论

      本文标题:关于动态规划的一点探究

      本文链接:https://www.haomeiwen.com/subject/yojamctx.html