动态规划理论基础

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。

动态规划五部曲:

  1.  确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

Dubug

  • 找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的!
  • 做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。 然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。 如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。 如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。

LeetCode 509. 斐波那契数

思路

动态规划五部曲:

1. 确定dp数组(dp table)以及下标的含义。
一个数组,下标表示序列从哪里开始。
2. 确定递推公式
F(n) = F(n-1) + F(n-2)
3. dp数组如何初始化
下标0和下标1需要进行默认初始化,后续下标为n的元素需要通过下标为n-1和n-2的元素相加得到。dp数组长度等于n+1。
4. 确定遍历顺序
遍历顺序:下标从小到大进行遍历。
5. 举例推导dp数组
print递推后dp数组

Code

class Solution(object):def fib(self, n):""":type n: int:rtype: int"""dp = [0] * (n+1)  ## dp数组的初始化,且确保总能获取到F(n),F(n)的最小数组长度为n+1if n >= 1:dp[1] = 1if n == 0:      ## 特殊情况处理return 0elif n == 1:return 1length = len(dp)for i in range(2,length):     ### 左闭右开,遍历顺序dp[i] = dp[i-1] + dp[i-2] ### 遍历公式 + dubug查看dp数组return dp[n]

LeetCode 70. 爬楼梯

思路

回溯算法也可以解决,但会存在超时的问题。Code如下:

class Solution(object):def climbStairs(self, n):""":type n: int:rtype: int"""self.path = []self.total = 0self.sum = 0nums = [1, 2]self.backtracking(nums, n, 0)return self.sumdef backtracking(self, num, n, start_index):if self.total == n:self.sum += 1return if self.total > n:return for i in range(start_index, len(num)):self.path.append(num[i])# print("self.path", self.path)self.total += num[i]# print("self.total", self.total)self.backtracking(num, n, 0)self.total -= num[i]self.path.pop()

这道题的题目关键不是在于排序组合的获取(即你走到这阶台阶的过程),而是在于迈向更高台阶方法数目和低台阶方法数目的联系。

台阶方法数目
1阶1种方法( [1] )
2阶2种方法( [1,1], [2] )
3阶3种方法( [1,1,1], [1,2], [2,1])
4阶5种方法( [1,1,1,1], [1,2,1], [2,1,1], [1,1,2], [2,2])
......

从上述方法数目我可以看得出到第N阶的方法总数F(N)其实就是F(N-1)+F(N-2) —— 递归公式。

为什么会有这种规律。因为迈的步子只为1和2,因此如果你迈的步子为2,那么从F(N-2)迈向F(N),可以通过只迈2步实现,因此F(N)的方法总数中包含了F(N-2)。另外,如果你迈的步子为1,那从F(N-1)迈向F(N)可以通过只迈一步实现,可以F(N)的方法总数中包含了F(N-1),这就是为什么是F(N) = F(N-1) + F(N-2)。

递归五部曲:

1. 确定dp数组(dp table)以及下标的含义。
下标为0,表示迈1阶。因此迈的阶数 = 下标 + 1。
2. 确定递推公式
F(N) = F(N-1) + F(N-2)
3. dp数组如何初始化
因为后续相加是涉及到N-1和N-2,因此前两个元素需要手动初始化。dp数组的长度 == 阶数(n)。
4. 确定遍历顺序
从前向后遍历更新dp数组。
5. 举例推导dp数组
print递推后dp数组

Code

class Solution(object):def climbStairs(self, n):""":type n: int:rtype: int"""dp = [0] * nif n == 1:return 1if n >= 1:dp[0] = 1   ## 迈向第一级台阶的方法数目dp[1] = 2   ## 迈向第二级台阶的方法数目length = len(dp)for i in range(2,length):dp[i] = dp[i-1] + dp[i-2]return dp[n-1]

其实递推公式和遍历顺序跟斐波那契数是一样的,只不过在数组长度初始化和前两个值的初始化上有区别。

LeetCode 746. 使用最小花费爬楼梯

容易陷入贪心的思路,即每次只与前面的元素的判断,通过大小来选择局部最优。如下所示:

[1,100,1000,200]。如果贪心思路的话,你前两个元素就会选择1,指针右移一位,后续选择100,指针右移后续选择200,这样的话总cost == 301,但实际上,从100可以直接到200,总cost == 300。

动规五部曲:

1. 确定dp数组(dp table)以及下标的含义。
dp[i]表示跳到第 i 个台阶时需要花费的cost。
2. 确定递推公式
dp[i] = min( dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
即判断表示从第i-1个台阶出发跳1个台阶的花费,和从i-2个台阶出发跳2个台阶的花费。第i-1个台阶和第i-2个台阶已经分别包含了之前跳到当前这个台阶的花费。
3. dp数组如何初始化
是跳的这个操作才需要花费,因此当处于第1个台阶和第2个台阶时,此时花费为0。因此dp[0] == dp[1] == 0
4. 确定遍历顺序
从前向后遍历更新dp数组。
5. 举例推导dp数组
print递推后dp数组

Code

class Solution(object):def minCostClimbingStairs(self, cost):""":type cost: List[int]:rtype: int"""### 到达超出数组长度的下标就是到达楼梯顶部了。length = len(cost)dp = [0] * lengthif length > 2:for i in range(2, length):dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])### 距离楼梯顶部差一个台阶 / 两个台阶时需要进行比较     one_step_cost = dp[length-1] + cost[length-1]two_step_cost = dp[length-2] + cost[length-2]if one_step_cost > two_step_cost:return two_step_costelse:return one_step_cost

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914458.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914458.shtml
英文地址,请注明出处:http://en.pswp.cn/news/914458.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

暑期自学嵌入式——Day02(C语言阶段)

点关注不迷路哟。你的点赞、收藏,一键三连,是我持续更新的动力哟!!! 主页: 一位搞嵌入式的 genius-CSDN博客https://blog.csdn.net/m0_73589512?spm1000.2115.3001.5343 目录 Day02→数据类型&#xf…

如何单独安装设置包域名

前言 在 npm 中,直接通过 package-lock.json 无法单独设置包的安装地址,因为该文件是自动生成的依赖关系锁定文件。但你可以通过以下方法间接实现: 一、在 package.json 中指定包来源(推荐) 在 package.json 的 depend…

存储过程探秘:数据库编程的艺术

文章目录存储过程语法格式BEGIN...END语句块DECLARE(声明局部变量)流控制语句if函数批处理操作测试2测试3存储过程与函数的关系存储过程 MYSQL的存储过程是一组预处理的SQL语句,可以像函数一样在数据库中进行存储和调用。 它们允许在数据库…

非阻塞写入核心:asyncio.StreamWriter 的流量控制与数据推送之道

在 asyncio 的异步编程框架中,如果说 asyncio.StreamReader 是你异步应用的数据输入管道,那么 asyncio.StreamWriter 就是你异步应用的数据输出管道。它是一个至关重要的组件,让你能够方便、高效且非阻塞地向连接的另一端(如 TCP …

控制台打开mysql服务报错解决办法

控制台打开mysql服务报错解决办法这个MySQL错误表示访问被拒绝,通常是因为没有提供正确的用户名和密码。以下是几种解决方法: 方法1:指定用户名和密码连接 mysql -u root -p然后输入root用户的密码。 方法2:如果忘记了root密码&am…

Unsloth 实战:DeepSeek-R1 模型高效微调指南(下篇)

食用指南 本系列因篇幅原因拆分为上下两篇: 上篇以基础环境搭建为主,介绍了 Unsloth 框架、基座模型下载、导入基座模型、数据集下载/加载/清洗、SwanLab 平台账号注册。 下篇(本文)以实战微调为主,介绍预训练、全量…

Ubuntu安装Jenkins

Ubuntu安装Jenkins方法1:使用官方的Jenkins仓库1. 添加Jenkins仓库2. 更新软件包列表3. 安装Jenkins4. 启动Jenkins服务5. 设置Jenkins开机启动6. 查找初始管理员密码7. 访问Jenkins方法2:使用Snap包(适用于较新的Ubuntu版本)1. 安…

ubuntu22.04下配置qt5.15.17开发环境

自从qt5.15版本开始,不再提供免费的离线安装包,只能通过源码自行编译。刚好最近需要在ubuntu22.04下配置qt开发环境,于是写篇文章记录配置的过程。 其实一开始是想配置qt5.15.2的,但是在编译配置参数这一步骤中出现如下报错 em…

S7-1200 与 S7-300 CPS7-400 CP UDP 通信 Step7 项目编程

S7-1200 CPU 与S7-300 CP STEP7 UDP通信S7-1200 与 S7-300 CP 之间的以太网通信可以通过 UDP 协议来实现,使用的通信指令是在S7-1200 CPU 侧调用通信-开放式用户通信TSEND_C,TRCV_C指令或TCON,TDISCON,TUSEND,TURCV 指…

基于YOLOv11的无人机目标检测实战(Windows环境)

1. 环境搭建 1.1 硬件与操作系统 操作系统:Windows 11 CPU:Intel i7-9700 GPU:NVIDIA RTX 2080(8GB显存) 1.2 安装CUDA和cuDNN 由于YOLOv11依赖PyTorch的GPU加速,需要安装CUDA和cuDNN: 安…

Spring Cloud分布式配置中心:架构设计与技术实践

从单体到微服务:Spring Cloud 开篇与微服务设计 Spring Cloud服务注册与发现:架构设计与技术实践深度分析 在以往分享中,码友们已经掌握了微服务的设计和注册中心的设计,部分聪明的码友已经察觉了,已经到了需要设计一个…

15.2 Common Criteria合规

目录1. Common Criteria简介1.1 CC评估要素1.2 CC与TF-A的关系2. TF-A的CC合规要求2.1 安全功能需求2.2 开发过程要求3. TF-A的CC合规实现3.1 关键安全机制3.2 开发流程控制4. CC认证实践指南4.1 认证准备步骤4.2 典型挑战与解决方案4.3 已认证案例参考5. 持续合规建议1. Commo…

【前端:Typst】--let关键字的用法

在 Typst 中,#let 命令是用于定义变量和函数的核心指令,其用法非常灵活。以下是详细的用法说明和示例。 目录 1.基础变量定义 2.函数定义 3.默认参数 4.内容块参数(Content Blocks) 5.递归函数 1.基础变量定义 // 定义简单…

Qt轮廓分析设计+算法+避坑

轮廓分析拟合方面我现在只考虑矩形拟合和圆形拟合细分的话,椭圆拟合,矩形拟合,最小外接矩形,最小外接圆。对于一张图像可能有不同的图形,不同的圆,不同的矩形,我需要对其进行筛选,也…

C++中STL六大组件List的简单介绍

一、前言C非常重视效率&#xff0c;对效率有损失的代码常常是能省则省。使用list要包含的头文件是<list>&#xff0c;要包含头文件就是#iinclude <list>&#xff0c;List肯定是一种链表&#xff0c;我们不妨回忆一下那种链表插入删除效率最快也就是最简单&#xff…

第十五节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - vue前端 生产部署

Vben Admin vben5 系列文章目录 💻 基础篇 ✅ 第一节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 ✅ 第二节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Python Flask 后端开发详解(附源码) ✅ 第三节:Vben Admin 最新 v5.0 (vben5) + Python …

背包初步(0-1背包、完全背包)

当月光洒在我的脸上 我想我就快变了模样 有一种叫做撕心裂肺的汤 喝了它有神奇的力量 动态规划初步&#xff08;完全背包&#xff09; 目录动态规划初步&#xff08;完全背包&#xff09;0-1背包简介完全背包检查数组是否存在有效划分&#xff08;前缀划分DP&#xff09;单词拆…

Linux驱动06 --- UDP

目录 一、UDP 1.1 介绍 1.2 UDP 的通信方式 1.3 单播 发送函数 接收函数 1.4 广播 1.5 组播/多播 一、UDP 1.1 介绍 传输层的另外一个协议 面向无连接&#xff0c;不稳定&#xff0c;速度快&#xff0c;可以一对多 UDP&#xff08;User Datagram Protocol&…

AJAX 投票:技术解析与应用场景

AJAX 投票:技术解析与应用场景 引言 随着互联网技术的不断发展,Web应用的用户体验越来越受到重视。AJAX(Asynchronous JavaScript and XML)作为一种重要的技术,在实现异步数据交互方面发挥着关键作用。本文将深入探讨AJAX投票系统的技术原理、应用场景以及优化策略。 A…

【字节跳动】数据挖掘面试题0017:推荐算法:双塔模型,怎么把内容精准地推送给用户

文章大纲 双塔模型:推荐算法中的“高效匹配引擎一、双塔模型的核心思想:“分而治之” 的匹配逻辑二、双塔模型的结构:从特征输入到相似度输出1. 输入层:特征的 “原材料处理”2. 塔网络层:用户与物品的“个性化编码”3. 交互层:向量相似度的“偏好打分”三、双塔模型的优…