数据结构中动态规划应该算得上是你避不开的一道槛了吧!其重要性不言而喻,今天就整理下学习笔记分享出来。希望对读者朋友也能有帮助,文章基本框架如下:

  • 什么是动态规划

  • 小偷的背包问题

  • LeetCode刷题

什么是动态规划

定义

动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

上述是维基百科的解释。能够看的出来最为关键的点有这样3个。

  • 最优子结构

  • 最小子问题边界

  • 状态转移函数(拆分转化方法)
    最优子结构指的是某一阶段复杂问题可以拆解成之前某些阶段的子问题;边界则是指对于最小子问题的解;状态转移方法指的是复杂某阶段复杂问题和之前阶段的转化关系。

举例解释

我们可以以斐波那契数列(Fibonacci)为例!

1, 1, 2, 3, 5, 8, 13 ,21 …

如果把第n个斐波拉契数记作 F(n),那么怎样利用动态规划来解释这个问题呢?

先谈最小子问题边界,当然是最前边的两个数F(1)和F(2)。

F(1)=F(2)=1。

最优子结构则是当前阶段斐波拉契数可以由之前斐波拉契数计算而出,计算关系则是我们说的状态转移方法。这里的状态转移函数为:

F(n)=F(n-1)+F(n-2),n>2

小偷的背包问题

上述斐波拉契数的例子只是用来举例便于理解动态规划的3个特点。真正经典的动态规划题目是小偷的背包问题:

一个小偷闯进一家珠宝店,他只背了一个可承重W的背包,珠宝店里有N件物品,其重量分别为w1,w2……wN,其价值分别为v1,v2……vN。那么问题来了,小偷该选择偷哪些东西用背包带走呢?(假设都为整数单位)

用动态规划的思路来解决这个题目,可以把物品的种类和书包承重力当成状态,绘制出一个二维表格如下,行表示种类从1到N,列表示承重从0到W。

0 1 …… W
1
2
……
N

再定义2个列表存储N类物品各自的重量和价值:

w=[w1,w2,……wN]
v=[v1,v2,^vN]

先思考整体过程

首先假设只有一件物品重量w[0]价值v[0],假设背包承重能力从0到W,被偷的最大价值为res,也就是第一行从左到右的过程。

不难想象,这时只用判断背包承重是否能够承受第一行对应物品,不能则res=0,能则被偷走,res=v[0]。

0 1 …… W
1 0 v[0] …… v[0]
2
……
N

确定第一行(边界)不难,关键在于如何找到状态转移函数,即res[i][j]是如何从之前状态获取计算的。res[i][j]表示共i+1件物品,j承重的时候,能偷走的最大价值。(加1是因为列表索引从0开始)

选择边界并确定状态转移函数

重点来了!当已知res[i-1][:]所有状态,现在有第i+1件物品可以选择,我们该怎么判断?

首先判断第i+1件物品是否超出背包当前承重(即w[i]>j),超出则肯定放不进去,最大价值和有无第i+1件物品无关,即res[i][j]=res[i-1][j]。

当可以放进去的时候,有两个选择,放或不放,选择不放该物品,则依旧是res[i][j]=res[i-1][j];选择放该物体则最大价值是res[i][j]=v[i]+res[i-1][j-w[i]],表示放了之后剩余载重可带走的最大价值。

两种选择取其大者即可!上述逻辑代码如下,也是核心代码。

for i in range(1,N):#从第二行开始    for j in range(C+1):        #这里是关键的状态转移函数        if j < w[i]:            res[i][j] = res[i-1][j]        else:            res[i][j] = max(res[i-1][j], v[i]+res[i-1][j-w[i]])#注意这里,应当设置承重为0的情况(即j从0到C+1);可能存在j=w[i]

return res

当返回了res后,其实res[N-1][C]即为所求的最大价值。

但是!如果我要你告诉我你选择哪几件物品的时候能取得上述最大值呢?思考一分钟再往后看!

其实,这会我们反过来看就比较简单了,因为上述核心就是对比res[i][j]和res[i-1][j],能够想到如果二者不相等的时候,必然说明res[i][j]对应的物品偷走了(没偷走二者应当相等),若取走了该件物品,背包载重则减少了对应的承重。所以这样就能够判断出小偷偷走的是那些物品了,需要注意的是当i=1的时候无法判断res[0][j]对应行是否偷走,这里应当利用剩余承重是否为0了。

有点绕口,基本上是逐行把自己代码的思路讲解出来的,而不是直接给代码,希望对小白友好些。

代码实现

talk is cheap,show me the code:

# Author:小詹#Date:2019-4-18#动态规划的背包类问题,Python实现

def bag(N,C,w,v):    '''    N:物品种类    C:背包承重    w:物品种类对应的重量,列表    v:物品种类对应的价值,列表    '''    res = [[0 for j in range(C+1)] for i in range(N)] #全0表格,1-N件物品,0-C承重

    for j in range(C+1):#初始化第一行边界        if j < w[0]:            res[0][j] = 0        else:            res[0][j] = v[0]#     print(res)

    for i in range(1,N):#从第二行开始        for j in range(C+1):            #这里是关键的状态转移函数            if j < w[i]:                res[i][j] = res[i-1][j]            else:                res[i][j] = max(res[i-1][j], v[i]+res[i-1][j-w[i]])#注意这里,应当设置承重为0的情况(即j从0到C+1);可能存在j=w[i]

    return res

def show(N,C,w,res):    '''    通过比较res[i][j]和res[i-1][j]是否相等判断是否装了第i+1件物品;    小詹这里没有充分发挥列表下标从0开始的特点,导致要做+1操作,能理解就好    '''    print('背包能放下物体最大价值为:',res[N-1][C])    print(res)

    j = C    pick = []

    for i in range(N-1,0,-1):#         print(i)        if res[i][j] > res[i-1][j]:        #因为res中从0开始是第1行,这里i-1对应第i行;将第i行和i-1行对比,如果不一样则表示背包装了第i行对应的物品            pick.append(i+1)            j-=w[i-1]                   if j > 0:        pick.append(1)

    print('背包依次装了第',pick,'件物品')

def main():    N = 5    C = 10    w = [2, 2, 6, 5, 4]    v = [6, 3, 5, 4, 6]

    res = bag(N,C,w,v)    show(N,C,w,res)

if __name__ =='__main__':    main()    

上述就是完整代码。(码字不易,转用请注明出处)

LeetCode刷题

嗯哼,如果你把前两部分彻底搞懂了,对动态规划至少也算是有个初步了解了吧!

熟能生巧,当然得在力扣上找点题目练练手吧?这里有3道题可以去尝试一下噢!

1.LeetCode第5题————最长回文字串
2.LeetCode第10题————正则表达式匹配
3.LeetCode第32题————最长有效括号
4.Leetcode第62题————不同路径
5.Leetcode第63题————不同路径2

其中第5题和第10题可以参考小詹之前打卡记录帖~
LeetCode打卡系列1-20题~

点击阅读原文可查看小詹博客对应内容噢!

数据结构之动态规划问题相关推荐

  1. 【恋上数据结构】动态规划(找零钱、最大连续子序列和、最长上升子序列、最长公共子序列、最长公共子串、0-1背包)

    动态规划(Dynamic Programming) 练习1:找零钱 找零钱 - 暴力递归 找零钱 - 记忆化搜索 找零钱 - 递推 思考题:输出找零钱的具体方案(具体是用了哪些面值的硬币) 找零钱 - ...

  2. 【数据结构】动态规划——找零钱问题解析(含c++和python代码)

    一个具体的找零钱问题: 参考:程序员面试再也不怕动态规划了,看动画,学DP,找零钱 (LeetCode 322) 硬币面值:1,2,5,7,10 找零金额:14 step1:定义长度为15的dp数组 ...

  3. 【算法与数据结构】—— 动态规划之背包问题

    动态规划之背包问题 前面介绍了一些最常见的动态规划题型和对应解法,而实际上,动态规划最经典的题型非背包问题莫属,并且大多数人最初都是从背包问题入坑进而打开动态规划这一大门. 背包问题分为多种,其中最常 ...

  4. 面经系列 | Python,数据结构,神经网络

    本文转自Datawhale,禁二次转载 目录 人工神经网络中为什么ReLu要好过于tanh和sigmoid function? MLE的解是否总是存在,若存在是否唯一? L1用于逻辑回归,C 值从 0 ...

  5. 数据结构与算法系列——从菜鸟到入门

    持续更新系列. 参考自:<数据结构与算法分析--Java语言描述>.<算法导论> 排序 数据结构--快速排序 数据结构--堆排序 数据结构--归并排序 数据结构--计数排序 数 ...

  6. 算法竞赛知识合集 目录(博客中转站)

    目录 0x00. 基本算法 0x01. 基本算法 - 位运算 0x02. 基本算法 - 递推与递归 0x03. 基本算法 - 前缀和与差分 0x04.基本算法 - 二分和三分 0x05.基本算法 - ...

  7. 洛谷 - 试炼场(全部题目备份)

    整理的算法模板合集: ACM模板 目录 1.新手村 1 - 1 洛谷的第一个任务 1 - 2 顺序与分支 1 - 3 循环!循环!循环! 1 - 4 数组 1 - 5 简单字符串 1 - 6 过程函数 ...

  8. 把握春招,收下这份GitHub万星的ML算法面试大全!

    来源:机器之心 本文约2380字,建议阅读7分钟. 在本项目中,作者为大家准备了 ML 算法工程师面试指南,它提供了完整的面试知识点.编程题及题解.各科技公司的面试题锦等内容. [导 读]春季到来,春 ...

  9. 这份GitHub万星的机器学习算法面试大全请大家注意查收

    https://www.toutiao.com/a6677723633890099715/ 实习季已经开始,秋招也需要进入准备阶段.小编给大家带来一个好的项目中,作者为川大研究生,为大家准备了 ML ...

最新文章

  1. NoSQL and Redis
  2. STM32下一次程序后J-link不能识别问题解决
  3. 汉文博士 0.5.6 正式版发布
  4. python断点调试_「Python调试器」,快速定位各种疑难杂症!!!
  5. 蓝桥杯---等差数列(C语言)
  6. 关于新版VLC无法看RTSP的视频的问题-转
  7. 教你如何预判用户手势行为
  8. ios opencv图片处理_iOS_OpenCV图片轮廓检测
  9. 如何自定义一个注解(@Annotation)
  10. 平稳与非平稳序列的拟合及预测
  11. 电信光纤猫虚拟服务器设置方法,电信光纤无线路由器(光猫)的设置方法
  12. 电阻参数_电阻的基础知识和参数介绍
  13. 证明:凸多边形裁剪一次最多能够新增一个凸多边形
  14. python excel转csv日期变数字_将Excel转换为CSV正确转换日期字段
  15. JavaScript 内置对象
  16. Tensorflow版本更新命令
  17. JDK12 ShenandoahGC小试牛刀
  18. OA项目实战学习(1)
  19. 环信im Flutter sdk使用帮助
  20. Davinci-国产开源数据可视化工具

热门文章

  1. 反思深度思考:不无脑的行动 有脑的持久行动
  2. Linux之查看ubuntu版本
  3. Git强制覆盖还原本地救火命令
  4. python实现分布式_Python如何快速实现分布式任务
  5. java视频流传输_java – 使用Xuggler流式传输视频
  6. android调用百度活体检测接口,C#调用百度API实现活体检测的方法
  7. c语言宿舍管理查询软件,宿舍管理查询软件--数据结构,c语言
  8. 【SSL】【Apache】 使用向导配置 https/ssl
  9. 【若依(ruoyi)】swagger 接口 @ApiModelProperty 添加枚举值说明
  10. cmd窗口设置charset