本文素材来自视频,请自备梯子观看:What Is Dynamic Programming and How To Use It

Dynamic Programming:动态编程分为如下几步:

  1. 将复杂问题拆分成多个较简单的子问题
  2. 对每个子问题只计算一次,然后使用数据结构(数组,字典等)在内存中存储计算结果
  3. 子问题的计算结果按照一定规则进行排序(如,基于输入参数)
  4. 当需要再次运算子问题时直接使用已存储的计算结果而非再次运算以提升求解性能

这种存储计算结果以备再次使用称之为:Memoization(这个词,不知道怎么翻译好)

以斐波那契数列为例来说明:

1、使用递归实现:

def fib(n):
if n < 1:
raise ValueError('参数n必须为大于0的整数')
if n == 1 or n == 2:
return 1
return fib(n-2)+fib(n-1)

这种方法是经典的递归运算。以fib(5)为例,整个求解过程可以拆分为:

 
 

我们可以看出,fib(2)被计算三次,fib(3)与fib(1)各被计算2次,时间复杂度为O(2^n)。

2、对递归进行改进

def fib_memory(n):
d = dict()
_fib_memory(n, d) def _fib_memory(n, temp_dict):
if n < 1:
raise ValueError('参数n必须为大于0的整数')
if type(temp_dict) is not dict
raise TypeError('参数temp_dict必须为dict类型')
if n in temp_dict:
return temp_dict[n]
if n == 1 or n == 2:
result = 1
else:
result = fib_memory(n-1, temp_dict)+fib_memory(n-2, temp_dict)
temp_dict[n] = result
return result
 

优化后,时间复杂度降为O(n)。优化后的算法依然使用了递归,当参数较大时(如,1000)会导致栈溢出:
RecursionError: maximum recursion depth exceeded in comparison

3、脱离递归:

def fib_bottom_up(n):
l = [None]*(n+1)
return _fib_bottom_up(n, l) def _fib_bottom_up(n, temp_list):
if n < 1:
raise ValueError('参数n必须为大于0的整数')
if type(temp_list) is not list:
raise TypeError('参数temp_list必须为list类型')
if temp_list[n] is not None:
return temp_list[n]
if n == 1 or n == 2:
return 1
temp_list[1] = 1
temp_list[2] = 1
for i in range(3, n+1):
temp_list[i] = temp_list[i-1]+temp_list[i-2]
return temp_list[n]
 
 

改进之后的算法不再使用递归,时间复杂度依然是O(n)。


对以上三种实现编写测试用例:

# coding=utf-8

import temp
import unittest class TestDif(unittest.TestCase):
def test_fib_0_throw_value_error(self):
with self.assertRaises(ValueError):
temp.fib(0) def test_fib_1_return_1(self):
result = temp.fib(1)
self.assertEqual(1, result) def test_fib_10_return_false(self):
result = temp.fib(10)
self.assertFalse(result == 10) def test_fib_memory_10_return_false(self):
result = temp.fib_memory(10)
self.assertNotEqual(result, 10) def test_fib_bottom_up_1000_return_true(self):
result = temp.fib_bottom_up(1000)
print(result)
self.assertTrue(result > 100000) if __name__ == "__main__":
unittest.main()

小结

无意中在Youtube上看到这段视频,就翻译整理下来与大家共享。

推荐阅读

Python知识梳理

动态编程(Dynamic Programming)的更多相关文章

  1. C# 4.0中的动态类型和动态编程

    # 4.0的主题就是动态编程(Dynamic Programming).虽然C#仍然是一种静态语言,但是对象的意义开始变得越来越“动态”.它们的结构和行为无法通过静态类型来捕获,或者至少编译器在编译程 ...

  2. 算法编程Algos Programming

    算法编程Algos Programming 不同算法的集合,用于编程比赛,如ACM ICPC. 算法按主题划分.大多数算法都可以从文件中按原样运行.每种算法都有一个参考问题,并对其时间和空间复杂度作了 ...

  3. 以计算斐波那契数列为例说说动态规划算法(Dynamic Programming Algorithm Overlapping subproblems Optimal substructure Memoization Tabulation)

    动态规划(Dynamic Programming)是求解决策过程(decision process)最优化的数学方法.它的名字和动态没有关系,是Richard Bellman为了唬人而取的. 动态规划 ...

  4. Java的动态代理(dynamic proxy)

    什么是动态代理(dynamic proxy) 动态代理(以下称代理),利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对 ...

  5. 十七、C# 反射、特性和动态编程

    反射.特性和动态编程   1.访问元数据 2.成员调用 3.泛型上的反射 4.自定义特性 5.特性构造器 6.具名参数 7.预定义特性 8.动态编程   特性(attribute)是在一个程序集中插入 ...

  6. [.NET] 《Effective C#》快速笔记 - C# 中的动态编程

    <Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...

  7. C# 4动态编程新特性与DLR剖析

    =================================================== 注:很久没有发文了,贴一篇新文吧.从Word直接贴过来的,没仔细排版,诸位海涵.有关DLR和C# ...

  8. [LeetCode] 121. Best Time to Buy and Sell Stock_Easy tag: Dynamic Programming

    Say you have an array for which the ith element is the price of a given stock on day i. If you were ...

  9. [LeetCode] 53. Maximum Subarray_Easy tag: Dynamic Programming

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

随机推荐

  1. xmlhttprequest readyState 属性的五种状态

    关于readystate五个状态总结如下: readyState 状态    状态说明(0)未初始化此阶段确认XMLHttpRequest对象是否创建,并为调用open()方法进行未初始化作好准备.值 ...

  2. 安装virtualbox出现2503、2502的错误提示解决方法

    安装virtualbox右键选择以管理员的身份打开即可

  3. Python序列结构--字典

    字典:反映对应关系的映射类型 字典(dict)是包含若干“键:值”元素的无序可变序列 字典中元素的“键”可以是python中任意不可变数据,例如整数.实数.复数.字符串.元组等类型可哈希数据,“键”不 ...

  4. Linux更新源汇总-18.9.7更新

    企业站 阿里云:https://opsx.alibaba.com/mirror 网易:http://mirrors.163.com/ 教育站 北京理工大学:http://mirror.bit.edu. ...

  5. 解读IEEE 7417的软件体系架构描述的概念模型

    本文将解读标准IEEE Std 1471-2000(密集型软件的体系结构描述推荐实施规程)的概念模型图部分,从中一窥作为软件架构师的进行架构设计的思考角度与策略.如果我们把世界当做一场游戏,现在要玩的 ...

  6. [升级说明] Senparc.Weixin.MP v14.8.11 (微信群发接口调整)

    升级内容:添加根据标签群发接口,重构原根据分组群发接口  参考微信文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp14811 ...

  7. Java中最常用的集合类框架之 HashMap

    一.HashMap的概述 HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构.      HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射 ...

  8. npm安装webpack失败(mac和window都可能会遇到这样的情况,以下问题主要以mac为例)

     问题描述:我想查看一下webpack的版本,于是输入了命令webpack -v, 结果如下图所示: 注:这里提示我们要安装webpack-cli,是因为到了webpack4, webpack 已经将 ...

  9. Kali学习笔记3:TCPDUMP详细使用方法

    Kali自带Wireshark,但一般的Linux系统是不带的,需要自行下载,并且过程略复杂 而纯字符界面的Linux系统无法使用Wireshark 但是,所有Linux系统都会安装TCPDUMP:一 ...

  10. Kali学习笔记1:Linux基本命令及安装Java

    ls -l 详细信息ls /dev/ -ls 很详细ls -a 显示隐藏ls -lh 方便看ls -lh --sort=size 按大小排序.开头的都是隐藏 cd /media/ 进入cd .. 上一 ...