赞
踩
视频地址:https://www.youtube.com/watch?reload=9&v=vYquumk4nWw
可以通过三个方式写出斐波那契数列:递归,备忘录,自底向上
1.递归
- def fib(n):
- if n == 1 or n == 2:
- result = 1
- else:
- result = fib(n - 1) + fib(n - 2)
-
- return result
使用递归的会产生大量的重复计算,比如要计算fib(5),就要多次计算fib(3),fib(2)等之前计算过的值,浪费很多的空间和时间,当n值变得很大的时候,计算时间成指数增长,时间复杂度为O(2^n)。
那么怎么去优化这个程序呢?我们可以将其之前计算过的fib值使用一个列表或者其他容器存储起来,当之后计算需要使用的时候就直接使用,不再去重复计算。这里就引入了备忘录的解决方法。
- # 函数传入两个参数,一个n和一个memo用来存储计算过的值
- def fib(n, memo):
- # 若第n个fib的值已经在memo中,就直接返回
- if memo[n] != None:
- return memo[n]
- if n == 1 or n == 2:
- result = 1
- else:
- result = fib(n - 1) + fib(n - 2)
- # 每次计算的结果都存入memo
- memo[n] = result
-
- return result
- # 伪代码,源码在下面
此时时间复杂度为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无关的常数。
3.确定一些初始状态(边界状态)的值
以“数字三角形”为例,初始状态就是底边数字,值就是底边数字值。
4. 确定状态转移方程
定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。
--------------------- 本文来自 ChrisYoung1314 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/baidu_28312631/article/details/47418773?utm_source=copy
图片上的都是伪代码,源码放在下面了。
- def fib_2(n, memo):
- if memo[n] is not None:
- return meno[n]
- if n == 1 or n == 2:
- result = 1
- else:
- result = fib_2(n - 1, memo) + fib_2(n - 2, memo)
- memo[n] = result
- return result
-
- def fib_memo(n):
- memo = [None] * (n + 1)
- return fib_2(n, memo)
- def fib_bottom_up(n):
- if n == 1 or n == 2:
- return 1
- bottom_up = [None] * (n + 1)
- bottom_up[1] = 1
- bottom_up[2] = 1
-
- for i in range(3, n + 1):
- bottom_up[i] = bottom_up[i - 1] + bottom_up[i - 2]
-
- return bottom_up[n]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。