动态规划的解题思想

1. 从斐波那契数列说起
斐波那契数 (通常用
F(n)表示)形成的序列称为 斐波那契数列 。该数列由0和1开始, ,后面的每一项数字都是前面两项数字的和。也就是:F(0) = 0, F(2) = 1
F(n) = F(n - 1) + F(n - 2),其中 n >= 2
给定
n,请计算F(n)。
当我们看完上述问题后,心中一阵窃喜:答案不就在题目当中吗。
于是马上就写出了如下代码:
#暴力递归
def fib(n):if n == 0 or n == 1:return nreturn fib(n - 1) + fib(n - 2)
不幸的是,当我们提交完代码后,大概率会收到 leetcode 的超时警告!why,接下来我们分析一下上述代码的执行情况。假设 n=5 时,具体的执行逻辑如下图所示:

我们不难发现 fib(3) 计算了两次。如果这个差距不够明显的话,我们可以假设 n=10,再去画执行逻辑图,就会发现需要重复计算的情况成指数级增长,这就是耗时的主要原因。
然后我们想出了一种空间换时间的方法,把每次 fib 函数计算的结果缓存到一个哈希表中,下次再遇到相同的数则无需计算,直接查表即可,这样就大大减少了运算量。
#备忘录递归
map = {}
def fib(n):if n == 0 or n == 1:return nelif n in map:return map[n]map[n] = fib(n - 1) + fib(n - 2)return map[n]
2. 何为动态规划
上述解法通常被命名为备忘录递归解法,事实上备忘录递归法和动态规划只是在实现上稍有不同,其核心思想和目标完全一致,拆分子问题,记住过往,减少重复计算,甚至个人认为备忘录递归就是广义上的动态规划。
动态规划就是将一个问题拆分为若干的子问题,直到子问题被解决,保存子问题结果,然后递推出原问题的答案。
同样是上面的例子,我们既然知道 1 和 2 的值,就能推算出 3,4....n 的值。
我们不妨来定义一个数组 nums,nums[i] 表示斐波那契的第 i 项,递推的给数组赋值,返回第 n 项即为所求结果。不过为了强调动态规划,我们通常会将这个数组命名为 dp(Dynamic Programming)。
#动态规划解法
def fib(n):if n < 2:return ndp = [0] * (n + 1)dp[0] = 0dp[1] = 1for i in range(2, n + 1):dp[i] = dp[i - 1] + dp[i - 2]return dp[n]
3. 何时&如何使用动态规划
通过上述的例子,相信大家已经对动态规划有了一些认识,那么什么情况下我们可以使用动态规划呢?
如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。
如何使用动态规划的思想解题呢?
-
找到相同问题(也叫重叠子问题),这个相同问题必须能适配不同规模
-
找到相同问题 不同规模之间的关系(这个关系叫状态转移方程)
-
找到问题的特殊解,然后递推出所有规模的解
(简单的理解就是:定义 dp 表格的含义,找出后边数据和前边数据的关系,然后依次填表,直到找出最终解)
本节比较抽象,大家可以看完下一节的经典题目后再回来理解。
4. 经典题目
还是回到上面的例子,我们之所以能很容易写出上面代码,是因为题目中已经把状态转移方程直接写到了题目中。而大部分情况这个方程并非那么明显,需要我们去分析,这也是动态规划的难点所在。
下面的几个经典题目,我们只分析出状态转移方程,不实现具体代码,目的是体会理解动态规划的套路。
4.1 打家劫舍
一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1] 输出:4 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
第一步找到重叠子问题,要适配所有的规模。因为这是一个一位数组所有使用 dp[i] 就能表示所有的规模,那么 dp[i]表示什么含义呢?表示小偷从 0-i 范围内可以偷窃的最高金额。
第二步列状态转移方程。分析下图前 i 项的最大值,包含两个情况,要么包含第 i 项要么不包含第 i 项。
如果不包含第 i 项, 则 dp[i] = dp[i-1]
如果包含第 i 项,由于相邻的房屋不能偷窃,则一定不能包含第 i-1 项,所以 dp[i] = dp[i-2] + 数组的第 i 项的值
由于求的是最优的结果 所以 dp[i] 应该是以上两种情况中值较大的情况。
列出方程 dp[i] = max(dp[i-1], dp[i-2]+nums[i])
第三步确定特殊解,当房屋数等于 1 时,最优解就是只偷一间;当房屋数等于 2 时,最优解就是偷价值较大的一间。
接下来递推填表,返回最终解。

4.2 不同路径
一个机器人位于一个
m x n网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
![]()
首先第一步,我们要找到重叠子问题,这些子问题要能适配所有的规模。这里有行也有列,所以我们需要两个参数来表示这个子问题 dp[i][j],表示的含义就是从开始走到第 i 行第 j 列的所有路径数。
第二步,确定状态转移方程。观察下图,我们会发现 dp[i][j]的路径数只和两个格子有关 dp[i][j-1]和 dp[i-1][j],且是他们两个的和,所以状态转移方程应该是 dp[i][j] = dp[i][j-1] + dp[i-1][j]
第三步,确定特殊解,第 1 行和第 1 列所有的数据都只有一种情况,要么一直向右走要么一直向下走,所以全部赋值为 1,然后递推填表,直到返回最终结果。

4.3 01 背包
有 n 件物品和一个最多能背重量为 w 的背包。第 i 件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
示例 1:
物品重量为:[1,3,4]
物品价值为:[15,20,30]
背包能背的最大重量为:4
输出最大价值:35
解释:背包可以放入 0 和 1 号商品,价值为 15+20=35,也可以只放 2 号商品,价值为 30。
第一步找重叠子问题,确定 dp 表含义。
按照前面的经验我们通常会将 dp[i]定义为 从 0 到 i 最优的情况,干脆我们也将 dp[i] 定义为 从 0 到 i 件商品中可选的最大价值。然而我们继续往下分析时,并没有找到不同规模问题之间的联系。
另一方面我们还可以从背包容量上拆分子问题,比如如果知道背包容量为 3 时的最大价值,是否可以推导出容量为 4 时的最大价值,经过一番思考计算,好像也找不到不同规模之间的联系。
此时聪明的你,一定能想到,要不然将以上两个纬度同时进行拆分找一下其中的规律。那么我们就会得到下面一个二维 dp 表。其中 dp[i][j] 表示从 0-i 中选择的物品放入容量为 j 的背包中的最大价值

第二步分析不同规模问题之间的联系,列出状态转移方程
此时有两种情况,i 物品选还是不选。此时状态表达式有了一个基本的雏形:
dp[i][j] = max(选第 i 件商品,不选第 i 件商品)。
首先看不选的情况,这种情况比较简单,如果不选那么最大价值就等于同等容积背包内,前面商品所能凑出的最大价值。直接写出表达式 dp[i][j] = dp[i-1][j]
接下来分析选的情况,如果选择了第 i 个商品 那么此时的最大价值应该是 商品i本身的价值 + 商品i-1范围内 且 背包容量为(j-商品i的重量)的最大价值,写成表达式为dp[i][j] = value[i] + dp[i-1][j-weight[i]]
综上最终的表达式为 dp[i][j] = max(dp[i-1][j], value[i] + dp[i-1][j-weight[i]]),另外还需要处理一些边界条件,例如当商品本身重量大于背包容量时等。此处就不展开描述了。
第三步找出特殊解
当物品下表为 0 时,之前看当前商品是否可以放入背包内,可以放入最大价值就是当前商品价值,否则最大价值就是 0,然后递推填表。
学到这里,恭喜你,你已经拿到了 leetcode 刷动态规划类题目的入场券!
5. 空间复杂度的优化
最后我们再来聊一下空间复杂度的优化。
上面我们说过,动态规划的核心就是记住过往,减少重复计算, 牺牲空间去换取时间,那么我们到底牺牲了多少空间?
回到斐波那契数列,我们定义了一个长度为 n 的数组来缓存过程中的计算结果,所以空间复杂度为 O(n),然后仔细观察我们就会发现,当我们计算 dp[i] 时,并不需要整个数组,而是只需两个数字。所以我们只需定义两个数据,每次记得更新数据即可。这样就可以将空间复杂度降低到常量级 O(1)。
接下来我们看不同路径的题目,在这里我们定义了一个二位数组,所以空间复杂度为 O(m*n);继续观察我们发现 dp[i][j] 只和当前行和上一行的数据关联。那我们就可以这样做,定义一个一维数组,先把数组全部填充 1(相当于二维数组的第一行),之后的行从左往右覆盖当前的一维数组,假设覆盖到了第 i-1 位,此时一位数组的含义,i 左边的数据表示的是当前行的数据,i 及右边的数据表示上一行的数据。原本的状态转移方程dp[i][j] = dp[i][j-1] + dp[i-1][j]就可以优化成 dp[i] = dp[i-1]+dp[i],空间复杂度也降到了 O(n)
这里总结出来,很多动态规划问题可以通过“空间降维”只缓存当前被需要的数据,来降低空间复杂度。
6. 团队介绍
「三翼鸟数字化技术平台-场景设计交互平台」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。
相关文章:
动态规划的解题思想
1. 从斐波那契数列说起 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始, ,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0, F(2) 1 F(n) F&…...
OpenCV结构分析与形状描述符(10)检测并提取轮廓函数findContours()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在二值图像中查找轮廓。 该函数使用算法 253从二值图像中检索轮廓。轮廓是有用的工具,可用于形状分析和对象检测与识别。参见 OpenC…...
HBase 源码阅读(二)
衔接 在上一篇文章中,HMasterCommandLine类中在startMaster();方法中 // 这里除了启动HMaster之外,还启动一个HRegionServerLocalHBaseCluster cluster new LocalHBaseCluster(conf, mastersCount, regionServersCount,LocalHMaster.class, HRegionSer…...
深度学习每周学习总结N9:transformer复现
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 目录 多头注意力机制前馈传播位置编码编码层解码层Transformer模型构建使用示例 本文为TR3学习打卡,为了保证记录顺序我这里写…...
数据结构与算法(3)栈和队列
1.前言 哈喽大家好啊,今天博主继续为大家带来数据结构与算法的学习笔记,今天是关于栈和队列,未来博主会将上一章《顺序表与链表》以及本章《栈与队列》做专门的习题应用专题讲解,都会很有内容含量 ,欢迎大家多多支持&…...
11、Django Admin启用对计算字段的过滤
重新定义admin.py中的Hero管理模型如下: admin.register(Hero) class HeroAdmin(admin.ModelAdmin):list_display ("name", "is_immortal", "category", "origin", "is_very_benevolent")list_filter ("…...
xxl-job升级到springboot3.0 导致页面打不开报错)问题
原因:springboot3.0 因为移除了jsp 导致xxl-job不能访问,解决方法如下 1、修改PermissionInterceptor拦截器 package com.xxl.job.admin.controller.interceptor;import com.xxl.job.admin.controller.annotation.PermissionLimit; import com.xxl.job.…...
栈和队列.
目录 1. 栈(Stack) 2. 栈的模拟实现 3. 栈的应用场景 4. 队列(Queue) 5. 队列的模拟实现 6. 循环队列 7. 双端队列(Deque) 8. 面试题 1. 栈(Stack) 栈:一种特殊…...
Parallel.ForEach - 并行处理
Parallel.ForEach 是 C# 中 System.Threading.Tasks.Parallel 类提供的一个方法,用于并行地迭代集合中的每一个元素。Parallel.ForEach 方法允许多个线程同时处理集合中的元素,从而提高程序的执行效率,特别是在处理大量数据或执行耗时任务时。…...
【MySQL】初识MySQL—MySQL是啥,以及如何简单操作???
前言: 🌟🌟本期讲解关于MySQL的简单使用和注意事项,希望能帮到屏幕前的你。 🌈上期博客在这里:http://t.csdnimg.cn/wwaqe 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 目…...
LLM应用实战: 产业治理多标签分类
数据介绍 标签体系 产业治理方面的标签体系共计200个,每个标签共有4个层级,且第3、4层级有标签含义的概括信息。 原始数据 企业官网介绍数据,包括基本介绍、主要产品等 企业专利数据,包括专利名称和专利摘要信息,且专…...
下载Mongodb 4.2.25 版本教程
1、MongoDB 安装包的下载链接 Download MongoDB Community Server | MongoDB 进入如下截图: 2、查找历史版本 往下拉,点击“...”,找到”Archived releases”,点击进入 、 3、下载Mongodb 4.2.25 版本 找到如下图4.2.25版本下载链接,点击就可…...
docker拉取redis5.0.5并建立redis集群
1.配置文件 mkdir -p redis-cluster/7001/ mkdir -p redis-cluster/7002/ mkdir -p redis-cluster/7003/ mkdir -p redis-cluster/7004/ mkdir -p redis-cluster/7005/ mkdir -p redis-cluster/7006/cd redis-clustervim 7001/redis.confbind 0.0.0.0port 7001cluster-enabled…...
React16新手教程记录
文章目录 前言一些前端面试题1. 搭建项目1. 1 cdn1. 2 脚手架 2. 基础用法2.1 表达式和js语句区别:2.2 jsx2.3 循环map2.4 函数式组件2.5 类式组件2.6 类组件点击事件2.6.1 事件回调函数this指向2.6.2 this解决方案2.6.2.1 通过bind2.6.2.2 箭头函数(推荐…...
怎么摆脱非自然链接?
什么是非自然链接? 非自然链接是人为创建的链接,用于操纵网站在搜索引擎中的排名。非自然链接违反了Google 的准则,网站可能会因此受到惩罚。 它们不是由网站所有者编辑放置或担保的。示例包括带有过度优化锚文本的链接、通过 PR 的广告、嵌…...
【2024数模国赛赛题思路公开】国赛B题第二套思路丨附可运行代码丨无偿自提
2024年数模国赛B题解题思路 B 题 生产过程中的决策问题 一、问题1解析 问题1的任务是为企业设计一个合理的抽样检测方案,基于少量样本推断整批零配件的次品率,帮助企业决定是否接收供应商提供的这批零配件。具体来说,企业需要依据两个不同…...
P1166 打保龄球
共可以投 1 局 一局10轮 在一局中,一共有十个柱,会出现很多种情况。 第1次把10个 打倒全部 >> 分数10后2次得分 --若是第10轮则还需另加两次滚球; 没全部打倒 >> 第2次把剩下的 打倒 >&g…...
[数据集][目标检测]西红柿成熟度检测数据集VOC+YOLO格式3241张5类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):3241 标注数量(xml文件个数):3241 标注数量(txt文件个数):3241 标注…...
数仓工具—Hive语法之URL 函数
hive—语法—URL 函数 业务需求中,我们经常需要对用户的访问、用户的来源进行分析,用于支持运营和决策。例如我们经常对用户访问的页面进行统计分析,分析热门受访页面的Top10,观察大部分用户最喜欢的访问最多的页面等: 又或者我们需要分析不同搜索平台的用户来源分析,统…...
c#如何实现触发另外一个文本框的回车事件
一.需求 我需要实现listview中的一行双击后,将其中的一个值传给一个文本框,传完后,给文本框一个回车指令。 我的方法:后面加上 \rthis.txt_ID.Text this.listView1.SelectedItems[0].Text"\r" 结果无效。 二.问通义…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
