动态规划的解题思想
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" 结果无效。 二.问通义…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...