动态编程(Dynamic Programming)
本文素材来自视频,请自备梯子观看:What Is Dynamic Programming and How To Use It
Dynamic Programming:动态编程分为如下几步:
- 将复杂问题拆分成多个较简单的子问题
- 对每个子问题只计算一次,然后使用数据结构(数组,字典等)在内存中存储计算结果
- 子问题的计算结果按照一定规则进行排序(如,基于输入参数)
- 当需要再次运算子问题时直接使用已存储的计算结果而非再次运算以提升求解性能
这种存储计算结果以备再次使用称之为: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上看到这段视频,就翻译整理下来与大家共享。
推荐阅读
动态编程(Dynamic Programming)的更多相关文章
- C# 4.0中的动态类型和动态编程
# 4.0的主题就是动态编程(Dynamic Programming).虽然C#仍然是一种静态语言,但是对象的意义开始变得越来越“动态”.它们的结构和行为无法通过静态类型来捕获,或者至少编译器在编译程 ...
- 算法编程Algos Programming
算法编程Algos Programming 不同算法的集合,用于编程比赛,如ACM ICPC. 算法按主题划分.大多数算法都可以从文件中按原样运行.每种算法都有一个参考问题,并对其时间和空间复杂度作了 ...
- 以计算斐波那契数列为例说说动态规划算法(Dynamic Programming Algorithm Overlapping subproblems Optimal substructure Memoization Tabulation)
动态规划(Dynamic Programming)是求解决策过程(decision process)最优化的数学方法.它的名字和动态没有关系,是Richard Bellman为了唬人而取的. 动态规划 ...
- Java的动态代理(dynamic proxy)
什么是动态代理(dynamic proxy) 动态代理(以下称代理),利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对 ...
- 十七、C# 反射、特性和动态编程
反射.特性和动态编程 1.访问元数据 2.成员调用 3.泛型上的反射 4.自定义特性 5.特性构造器 6.具名参数 7.预定义特性 8.动态编程 特性(attribute)是在一个程序集中插入 ...
- [.NET] 《Effective C#》快速笔记 - C# 中的动态编程
<Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...
- C# 4动态编程新特性与DLR剖析
=================================================== 注:很久没有发文了,贴一篇新文吧.从Word直接贴过来的,没仔细排版,诸位海涵.有关DLR和C# ...
- [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 ...
- [LeetCode] 53. Maximum Subarray_Easy tag: Dynamic Programming
Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...
随机推荐
- FPGA开发随笔汇总
点击标题即可进入相关随笔. DE-SOC开发板VrilogHDL开发相关部分: (本过程需要Verilog HDL 的基本语言基础) 1.FPGA的发展史及FPGA 的基础架构 2.首先看一下友晶DE ...
- python的基本数据类型(一)
一.运算符逻辑运算and:两边都真则真or:有真则真not:非假是真 顺序:()>==>not==>and>=or 二.while.. elsewhile 条件: 代码块els ...
- Mysql函数大全以及存储过程、函数、触发器、游标等等
https://www.cnblogs.com/slowlyslowly/p/8649430.html MySQL大全 存储过程: 基本语法 : create procedure sp_name([[ ...
- python基础学习记录一
1.如果脚本中带有中文(中文注释或者中文字符串,中文字符串前面需要在前面加u),且需要在文件头注明编码,并将UTF-8编码格式 #-*-coding:utf-8 -*- printf u'你好,WOR ...
- day_10初级函数
今天讲了函数初级 函数:完成特定功能的代码块,作为一个整体对其进行特定的命名,该名字就是代表函数 --现实中很多问题要通过一些工具进行处理 ,,可以将工具提前准备好并命名 通过名字就可以找到这个工具 ...
- linux下如何把php升级到5.6
1: 进入终端后查看php版本 php -v 输出可能如下: PHP (cli) (built: Nov ::) Copyright (c) - The PHP Group Zend Engine v ...
- canvas转图片中的文字自动换行
概述 最近项目用到了canvas转图片,但是由于canvas对文字排版的支持非常弱,一般我们在canvas上画不同排版的文字(比如竖排文字)都是利用js计算横纵坐标,然后一个字一个字地画出来,今天无意 ...
- mongoose的save无效的问题
概述 今天朋友遇到了使用mongoose中的save无效的问题,我通过查找资料帮他解决了,把心得记录下来,供以后开发时参考,相信对其他人也有用. 参考资料: Mongoose学习参考文档--基础篇 M ...
- 【详记MySql问题大全集】一、安装MySql
最近公司要从SqlServer转到MySql,期间在安装环境和数据迁移的过程中,遇到了一些不大不小问题,比如怎么重置密码.怎么设置大小写敏感等等. 这些问题都比较细比较杂,这边解决完可能过几天就忘了, ...
- Spring Boot 自定义日志详解
本节内容基于 Spring Boot 2.0. 你所需具备的基础 什么是 Spring Boot? Spring Boot 核心配置文件详解 Spring Boot 开启的 2 种方式 Spring ...