【算法】(Python)动态规划

动态规划:

  • dynamic programming。"programming"指的是一种表格法,而非编写计算机程序。
  • 通常解决最优化问题(optimization problem)。
  • 将问题拆分成若干个子问题,求解各子问题来得到原问题的解。
  • 适用于多阶段决策(以时间划分阶段的动态过程,可人为引进时间因素)。即一个活动过程可划分多个互相关联的阶段,每个阶段都需做决策,一个阶段的决策影响下一个阶段的决策,从而确定一个活动路线(即策略,每个阶段的决策组成的序列)。
  • 使用条件:最优子结构(一个问题最优解包含其子问题的最优解),重叠子问题(问题的递归算法会反复求解相同的子问题,而不是一直生成新的子问题)。
  • 每个子问题只计算一次,即有一个表记录每个子问题的解,再次需要该子问题时直接查表,无需重复计算。
  • 两种方法:带备忘的自顶向下(递归。从整体开始,拆分多个子问题递归求解),自底向上(迭代。先解决最小问题,进而解决整体问题)。通常使用自底向上。
  • 关键:解决冗余,以空间换时间(占用额外的内存,但节省计算时间)。
  • 缺点:“维数障碍”(维度增加,空间复杂程度呈指数级增长),没有统一的处理方法(具体问题具体分析)。


动态规划、分治方法、贪心算法,都是将问题分成若干个子问题,求解子问题从而得到原问题的解。

动态规划与分治方法的区别:

  • 动态规划的子问题相互重叠、不是独立的。分治方法的子问题互不相交、相互独立。
  • 动态规划的子问题只计算一次,并保存子问题的解。分治方法会计算每次出现的子问题。若同样的问题使用分治方法,则会重复计算相同的子问题。

动态规划与贪心算法的区别:

  • 动态规划寻求全局最优解(相关的子问题全部解决了,才能做出选择)。贪心算法是贪心地追求局部最优解(即当前状态下最优选择,求解选出的子问题的解),不一定全局最优解。


案例:

1、(难度:简单)【力扣】746. 使用最小花费爬楼梯

解题思路:台阶0和台阶1均可为起始点(即花费为0),此后,到达各台阶(含目的地)的最小花费:min(前1个台阶走1步到达的最小花费,前2个台阶走2步到达的最小花费)。有一个列表记录到达各台阶(含目的地)的最小累积花费。

知识点:min(a, b):从a和b中获取最小值。

class Solution:def minCostClimbingStairs(self, cost: List[int]) -> int:n = len(cost)           # 数组长度res = [0] * (n + 1)     # 记录到达各台阶和目的地的累积花费   # 从下标为0或1开始,花费为0,忽略# 从下标为2开始,判断前1个台阶到这和前2个台阶到这的累积最小花费,添加到结果列表中for i in range(2, n + 1):res[i] = min(res[i - 1] + cost[i - 1], res[i - 2] + cost[i - 2])# 返回到达目的地时的累积花费return res[n]

优化:各台阶(含目的地)花费涉及:前1个台阶走1步的花费,前2个台阶走2步的花费,其中最小的值。

设置3个变量:prev(当前台阶的前1个台阶,走2步到下一个需到达的台阶),curr(当前台阶,走1步到下一个需到达的台阶),next(下一个需到达的台阶)。

返回:最终到达当前台阶的累积最小花费。

class Solution:def minCostClimbingStairs(self, cost: List[int]) -> int:n = len(cost)           # 数组长度prev, curr = 0, 0       # prev:前1个台阶,curr:当前台阶# 从下标为0或1开始,花费为0,忽略# 从下标为2开始,计算到达该台阶的累积花费# 当前台阶走1步到下一个台阶和前1个台阶走2步到下一个台阶的累积最小花费for i in range(2, n + 1):next = min(curr + cost[i - 1], prev + cost[i - 2])prev, curr = curr, next          # 向后滚动移动return curr

python中itertools模块中pairwise可依次生成连续的两个元素。

itertools.pairwise(可迭代对象):返回迭代器,迭代器中为依次生成的连续的2个元素。

class Solution:def minCostClimbingStairs(self, cost: List[int]) -> int:n = len(cost)           # 数组长度prev, curr = 0, 0       # prev:前1个台阶,curr:当前台阶# 从下标为0或1开始,花费为0,忽略# 从下标为2开始,计算到达该台阶的累积花费# 当前台阶走1步到下一个台阶和前1个台阶走2步到下一个台阶的累积最小花费import itertoolsfor a, b in itertools.pairwise(cost):next = min(prev + a, curr + b)prev, curr = curr, next          # 向后滚动移动return curr

2、(难度:中等)【力扣】714. 买卖股票的最佳时机含手续费

解题思路:有一个二维数组,记录每一日最大收益:max(若当日手上没有股票时的最大收益,若当日手上有股票时的最大收益)

知识点:[ [ 0,0] ] * n:二维数组,有n个元素,元素类型仍为数组。即[[0,0],[0,0],...,[0,0]]。

               二维数组[0][1]:获取二维数组的第一个元素中下标为1的值。

               max(a, b):从a和b中获取最大值。

class Solution:def maxProfit(self, prices: List[int], fee: int) -> int:n = len(prices)# 二维数组初始化,记录[第i日手上没股票的收益,第i日手上有股票的收益]res = [[0, 0]] * n# 第1日(res列表中下标为0的元组),下标为0的值为0(第1日手上没有股票的收益),忽略# 第1日(res列表中下标为0的元组),下标为1的值为付出的买入价(第1日手上有股票的收益)res[0][1] = -prices[0]       # 遍历每日价格for i in range(1, n):# 当日,手上没有股票的收益:前1日也没股票,前1日有股票今天卖掉,取最大值res[i][0] = max(res[i - 1][0], res[i - 1][1] + prices[i] - fee)# 当日,手上有股票的收益:前1日也有股票,前1日没股票今天买入,取最大值res[i][1] = max(res[i - 1][1], res[i - 1][0] - prices[i])# 最后,手上没有股票收益更大return res[n - 1][0]

优化:今日收益涉及前1日手上是否有股票。滚动记录。

设置2个变量:zero(当日若手上没有股票时的收益)。one(当日若手上有股票时的收益)。

返回最终手上没有股票时的收益。

class Solution:def maxProfit(self, prices: List[int], fee: int) -> int:n = len(prices)# 第1日,zero:手上没有股票的收益,one:手上有股票的收益(付出的买入价)zero, one = 0, -prices[0]# 遍历每日价格for i in (range(1, n)):# 当日,手上没有股票的收益:前1日也没股票,前1日有股票今天卖掉,取最大值zero = max(zero, one + prices[i] - fee)# 当日,手上有股票的收益:前1日也有股票,前1日没有股票今天买入,取最大值one = max(one, zero - prices[i])# 最后,手上没有股票,收益最大return zero

 注:本题其他解题方法:贪心算法

3、(难度:困难)【力扣】871. 最低加油次数

解题思路:遍历每个加油站,先假设每到一个加油站都加油,i个加油站最多加油 i 次。

要求加油次数尽可能少,为避免重复加油,依次减少到达该加油站的加油次数(j从i到0),滚动调整加油 j 次后可行驶最大距离:max(已加油 j次 在本加油站不加油的最大距离,已加油 j-1次 在本加油站加油后最大距离)

最后遍历加油 j次后可行驶的最大距离,大于等于目的地的距离,则返回下标即加了几次油,否则无法到达目的地返回-1。

知识点:enumerate(可迭代对象):返回所有的元素下标和元素内容,元组形式。一般用于for循环。

class Solution:def minRefuelStops(self, target: int, startFuel: int, stations: List[List[int]]) -> int:       res = [0] * (len(stations) + 1)     # 记录每次加油后(含初始油量)可以行使的最大距离      res[0] = startFuel                  # 初始油量可以行使的最大距离# 遍历每个加油站for i, (long, fuel) in enumerate(stations):# 先假设每到一个加油站就加油,再减少到这的加油次数,滚动调整加油j次(i到0)后可行使的最大距离# 例如到达第3个加油站后最多加油3次:# 若加油3次最大行驶距离:max(已加油3次本次不加油最大距离, 已加油2次本次再加油后最大距离)# 若加油2次最大行驶距离:max(已加油2次本次不加油最大距离, 已加油1次本次再加油后最大距离)# 若加油1次最大行驶距离:max(已加油1次本次不加油最大距离, 已加油0次本次再加油后最大距离)            for j in range(i, -1, -1):      # 倒序,避免重复加油# 到达加油站后,才判断在这是否加油,以及加油j次后可行驶最大距离if res[j] >= long:res[j + 1] = max(res[j + 1], res[j] + fuel)# 遍历加油j次后的最大行使距离,超过目的地则返回下标即加了几次油for j, val in enumerate(res):if val >= target: return jreturn -1

注:本题其他解题方法:贪心算法

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

《无线重构世界》射频模组演进

射频前端四大金刚 射频前端由PA、LNA、滤波器、开关“四大金刚” 不同的模块有自己的工艺和性能特点 分层设计 射频前端虽然只由PA、LNA、开关、混频器4个模块构成,但不同模块之间相互连接且相互影响。如果将射频系统当成一个整体来理解,其中的细节和…

【C#】使用.net9在C#中向现有对象动态添加属性

在 C# 中向现有对象动态添加属性并不像在 Python 或 JavaScript 中那样容易,因为 C# 是一种强类型语言。 但是,我们可以通过使用一些技术和库来实现这一点,例如扩展方法、字典等。本文将详细介绍如何在 C# 中实现这一点。ExpandoObject 方法 …

编程语言之战:AI 之后的 Kotlin 与 Java

随着人工智能不断重塑科技格局,开发人员越来越面临选择哪些编程语言在 AI 开发方面最有利和有效的任务。 考虑到 AI 和机器学习的快速发展,一种编程语言是否更适合满足这一不断发展的领域的需求? 自 1995 年问世以来,Java 一直是编…

web前端

HTML HTML 超文本标记语言。 H5 HTML v5 get/post/delete/put ---- restful web开发 结构 样式动作 架构 装饰 交互 标签 文本相关 图片、图像、声音 导航 表格 列表 表单标签 布局标签 h5扩展 HTML入门 HBuilder安装 下载 运行HBuilder 创建workspace存储项目 创…

[react]10、react性能优化

1、列表&key 一、React更新流程 React在props或state发生改变时,会调用React的render方法,会创建一颗不同的树。React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI。 同层节点之间相互比较,不会垮节点比较;不同类型的节点&am…

基础网络安全知识

1.ctfhub技能树 1.1 Web-SQL注入 Web-SQL注入-整数型 && 字符型 && MySQL结构 参考:5.9.6MySql注入 Web-SQL注入-报错注入 step1: 查库名 ?id1 and extractvalue(1,concat(0x7e,database(),0x7e))-- step2: 查看表名 ?id1 and extractvalue(1…

一、初识C语言(1)

1.C语言识别的是二进制语言 C语言是一门计算机语言,计算机是硬件,硬件分通电(1)和 未通电(0)两种情况,所以C语言识别的都是0 / 1信号,也就是二进制语言。 2.C语言文件类型以及基本框…

传输协议设计与牧村摆动(Makimoto‘s Wave)

有一条活鱼和一条死鱼,你准备怎么做,你会将活鱼红烧或将死鱼清蒸吗?好的食材只需要最简单的烹饪,不好的食材才需要花活儿。 我此前的文字几乎都在阐述一个观点,广域网就是那条死鱼,数据中心则是那条活鱼。…

80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...

《架构师之路:架构设计中的100个知识点》 3.延时与吞吐量 有朋友问我说,架构优化时,什么时候要重点优化延时,什么时候要重点优化吞吐量? 画外音:补充阅读材料在最后。 延时(Latency)…

全星魅-物联网定位终端-北斗定位便携终端-北斗有源终端

在当今快速发展的物流运输行业中,精准定位与实时监控已成为确保货物安全与高效运输的关键因素。为了满足这一需求,QMCZ10作为一款集4G(LTE Cat1)通讯技术与智能定位功能于一体的终端产品,应运而生。它不仅具备普通定位…

网络编程(一):UDP socket api => DatagramSocket DatagramPacket

目录 1. TCP 和 UDP 1.1 TCP / UDP 的区别 1.1.1 有连接 vs 无连接 1.1.2 可靠传输 vs 不可靠传输 1.1.3 面向字节流 vs 面向数据报 1.1.4 全双工 vs 半双工 2. UDP socket api 2.1 DatagramSocket 2.1.1 构造方法 2.1.2 receive / send / close 2.2 DatagramPacket …

JDBC入门

什么是JDBC JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。 使用JDBC 使用JDBC会用到它…

ReactPress:深入解析技术方案设计与源码

ReactPress Github项目地址:https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议,欢迎一起共建,感谢Star。 ReactPress是一个基于React框架开发的开源发布平台,它不仅仅是一个简单的博客系统,更是一个功能全…

Linux挖矿病毒(kswapd0进程使cpu爆满)

一、摘要 事情起因:有台测试服务器很久没用了,突然监控到CPU飙到了95以上,并且阿里云服务器厂商还发送了通知消息,【阿里云】尊敬的xxh: 经检测您的阿里云服务(ECS实例)i-xxx存在挖矿活动。因此很明确服务器中挖矿病毒…

Stable Diffusion LoRA, LyCoris

本节内容,给大家带来的是stable diffusion的LoRA与LyCoris模型课程。我们在上节课程中,已经详细讲解了关于大模型的使用。在stable diffusion中打造一个大模型,需要基于大量特定特征的图像集进行训练,我们通常将这个过程称之为Dre…

[RoarCTF 2019]Easy Calc 1

[RoarCTF 2019]Easy Calc 1 审题 题目就是一个计算器。 看到源代码有 calc.php 进入看到waf的源代码 知识点 RCE 解题 审核代码 <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str $_GET[num];$blacklist [ , \t, \r, \n,\, &q…

文本转SQL(Text-to-SQL),场景介绍与 Spring AI 实现

在众多的 AI 大模型的应用场景中&#xff0c;Text-to-SQL&#xff0c;也就是文本转 SQL&#xff0c;是其中实用性很高的一个。Text-to-SQL 充分利用了大模型的优势&#xff0c;把用户提供的自然语言描述转换成 SQL 语句&#xff0c;还可以执行生成的 SQL 语句&#xff0c;再把查…

Oracle 23AI创建示例库

一、示例库介绍 多年来&#xff0c;Oracle 一直使用简单的数据库模式 SCOTT 及其两个突出的表 EMP 和 DEPT&#xff0c;用于文档和培训中的各种示例。但不少小伙伴并不知道如何创建这些示例数据&#xff0c;其实Oracle官方上就有提供对应的方法&#xff0c;本文就带领大家完成…

默认 iOS 设置使已锁定的 iPhone 容易受到攻击

苹果威胁研究的八个要点 苹果手机间谍软件问题日益严重 了解 Apple 苹果的设备和服务器基础模型发布 尽管人们普遍认为锁定的 iPhone 是安全的&#xff0c;但 iOS 中的默认设置可能会让用户面临严重的隐私和安全风险。 安全研究员 Lambros 通过Pen Test Partners透露&#…

微博舆情分析:使用Python进行深度解析

目录 一、准备工作 二、基础理论知识 三、步骤详解 数据预处理 情感分析 关键词提取 四、案例分享 数据爬取 数据分析 五、优化 六、结论 在当今信息爆炸的时代&#xff0c;社交媒体平台如微博已成为公众表达意见和情感的重要渠道。微博舆情分析通过对大量微博数据进…