本文素材来自视频,请自备梯子观看: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. Vue route部分简单高级用法

    一改变页面title的值   在开发时常常需要在切换到不同页面时改变浏览器的title值,那么我们就可以在定义路由的时候通过配置 meta 属性 来改变title值. import Vue from ...

  2. Python基础理论 - Python简介

    1. Python介绍 -程序员减少开发成本 创业性公司 - Python使用较多,开发效率高 老牌大公司 - 有部门使用 -应用领域 •自动化运维 -- 安装Linux 自带 Python -- 现 ...

  3. PHP中 PCRE正则表达式模式修饰符“u” 的使用。

    u (PCRE_UTF8) 此修正符打开一个与 perl 不兼容的附加功能. 模式字符串被认为是utf-8的. 这个修饰符 从 unix 版php 4.1.0 或更高,win32版 php 4.2.3 ...

  4. 写在HTTP协议之前

    1.网络模型 OSI模型即:开放系统互连参考模型(Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参 ...

  5. 笔记:安卓App消息处理机制

    内容简述 类似Binder机制,MessageQueue.Looper也有底层的C++实现,涉及文件管道和驱动等. 以下仅从Java层的Looper.Handler和MessageQueue等相关类型 ...

  6. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  7. IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

    1.前言 在IM这种讲究高并发.高消息吞吐的互联网场景下,MQ消息中间件是个很重要的基础设施,它在IM系统的服务端架构中担当消息中转.消息削峰.消息交换异步化等等角色,当然MQ消息中间件的作用远不止于 ...

  8. 吴恩达机器学习笔记41-支持向量机的优化目标(Optimization Objective of Support Vector Machines)

  9. Python爬虫-萌妹子图片

    最近发现一个可以看图的地方,一张张翻有点累,毕竟只有一只手(难道鼠标还能两只手翻?).能不能下到电脑上看呢,毕竟不用等网速,还可以预览多张,总之很方便,想怎么就怎么,是吧? 刚好这几天在学python ...

  10. Mysql学习笔记整理手册

    目录 (1) str_to_date (2) 递归查询 (3) 排序问题 (4) 条件函数 (5) 列转行函数 (6) find_int_set (7) 类型转换函数 (8) 合并更新 继上一篇博客& ...