当前位置:   article > 正文

动态规划入门----斐波那契数列(搬_问题a: 动态规划-fib数列

问题a: 动态规划-fib数列

视频地址:https://www.youtube.com/watch?reload=9&v=vYquumk4nWw

可以通过三个方式写出斐波那契数列:递归,备忘录,自底向上

1.递归

  1. def fib(n):
  2. if n == 1 or n == 2:
  3. result = 1
  4. else:
  5. result = fib(n - 1) + fib(n - 2)
  6. return result

使用递归的会产生大量的重复计算,比如要计算fib(5),就要多次计算fib(3),fib(2)等之前计算过的值,浪费很多的空间和时间,当n值变得很大的时候,计算时间成指数增长,时间复杂度为O(2^n)。

那么怎么去优化这个程序呢?我们可以将其之前计算过的fib值使用一个列表或者其他容器存储起来,当之后计算需要使用的时候就直接使用,不再去重复计算。这里就引入了备忘录的解决方法。

  1. # 函数传入两个参数,一个n和一个memo用来存储计算过的值
  2. def fib(n, memo):
  3. # 若第n个fib的值已经在memo中,就直接返回
  4. if memo[n] != None:
  5. return memo[n]
  6. if n == 1 or n == 2:
  7. result = 1
  8. else:
  9. result = fib(n - 1) + fib(n - 2)
  10. # 每次计算的结果都存入memo
  11. memo[n] = result
  12. return result
  13. # 伪代码,源码在下面

此时时间复杂度为O(2n+1) ---> O(n)远小于O(2^n)。还可以在备忘录的基础上继续优化,不使用递归来做,函数依然指传入第n个fib求解,函数中定义一个n+1长度的数组(列表),从1开始存储值,第一位是1,第二位也是1,这两项就是动态规划中的初始状态的值(边界状态),从第三项开始一直到n进行fib的计算,bottom_up[i] = bottom_up[i-1] + bottom_up[i - 2]就是动态规划要使用到的状态转移方程,最终返回列表顶部的数,自底向上方法也就是动态规划的方法求解的fib,时间复杂度也是O(n)。

   动规解题的一般思路

    1. 将原问题分解为子问题

  •     把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决(数字三角形例)。
  •     子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。

    2.确定状态

  •     在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
  •     所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个问题的状态空间里一共就有N×(N+1)/2个状态。

    整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。

    3.确定一些初始状态(边界状态)的值

    以“数字三角形”为例,初始状态就是底边数字,值就是底边数字值。

    4. 确定状态转移方程

     定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。

--------------------- 本文来自 ChrisYoung1314 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/baidu_28312631/article/details/47418773?utm_source=copy

图片上的都是伪代码,源码放在下面了。

  1. def fib_2(n, memo):
  2. if memo[n] is not None:
  3. return meno[n]
  4. if n == 1 or n == 2:
  5. result = 1
  6. else:
  7. result = fib_2(n - 1, memo) + fib_2(n - 2, memo)
  8. memo[n] = result
  9. return result
  10. def fib_memo(n):
  11. memo = [None] * (n + 1)
  12. return fib_2(n, memo)
  1. def fib_bottom_up(n):
  2. if n == 1 or n == 2:
  3. return 1
  4. bottom_up = [None] * (n + 1)
  5. bottom_up[1] = 1
  6. bottom_up[2] = 1
  7. for i in range(3, n + 1):
  8. bottom_up[i] = bottom_up[i - 1] + bottom_up[i - 2]
  9. return bottom_up[n]

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/573459
推荐阅读
相关标签
  

闽ICP备14008679号