python数据结构与算法 26 动态规划

26、深入理解Python中的高级数据结构与算法 本文深入探讨了Python中的高级数据结构与算法,包括列表、元组、字典、集合等基本数据结构及其操作,并介绍了搜索、排序、动态规划、回溯和贪心等常见算法。通过丰富的示例代码和实际应用案例,帮助读者更好地理解如何在实际编程中选择和优化数据结构与算法,以提升程序性能和代码质量。 阅读详情

动态规划

很多程序的目的在数值优化。象计算两地之间的最短距离,一个点集的最佳拟合曲线,符合某些条件的最小集合等。这些问题有很多的求解方法,本节的目标就是向你展示不同的问题解决策略。动态规划就是优化问题的解决方法之一。

找零问题是数值优化的经典问题之一,假设你是一个自动售货机厂商的程序员,公司决定,为每次找交易的找零,计算需要的最小的硬币数量,从而实现流程化。如果一个顾客投入了1美元,买了37美分的东西,需要最小的硬币是多少?答案是6个:2个25美分(译者:不知道作者为什么不使用50美分的硬币),1个10美分,3个1美分。答案怎么来的?我们从最大的硬币开始,尽可能多地使用大额硬币,直到余额不够这个面值,然后再尽可能多地使用第二面额的硬币,以此类推。这种方法叫做“贪婪方法”,因为我们总是对正在计算的问题,作出当前看来最好的结果。

贪婪方法在美国硬币问题上回答正确,但如果你的公司要把自动售货机出口到Lower Elbonia(译注:Elbonia 是系列漫画 Dilbert 中一个杜撰的原东欧共产主义国家。Lower Elbonia 指这国家的南部。),那里除了平时所用的1,5,10和25美分硬币,还有一种21美分的。这时贪婪算法就失灵了,因为它仍然会算出6个硬币,但正确答案是3个21美分的硬币。

我们在研究找出一种确保正确答案的方法。既然本章是在谈递归,你也许想到用递归解决。先说递归的基点开始。

如果我们要找的零钱,正好是某个硬币的面值,那就简单了,一个硬币。

如果找零和手上的硬币都对不上号,那么答案是以下四种情况的最小值:

从要找的零钱中拿掉一个1分币,计算余额最少需要多少硬币,然后加上这个硬币

从要找的零钱中拿掉一个5分币,计算余额最少需要多少硬币,然后加上这个硬币

从要找的零钱中拿掉一个10币,计算余额最少需要多少硬币,然后加上这个硬币

从要找的零钱中拿掉一个25分币,计算余额最少需要多少硬币,然后加上这个硬币。

也就是按以下公式计算:


以上算法的实现如下。第三行是查检基点,就是说看一下找钱是否就是某个硬币的面值,如果不是,就把找钱的值减去每种硬币的面值,然后依次递归计算。第6行加了一个过滤,就是只比较面币比找钱小的硬币,递归过程也一直在降低找钱的数值。第7行进行递归调用,注意这一行我们对硬币数量有一个加1的的过程,因为后面的递归是减少一个硬币的递归,趋向基点的过程。

Listing 7

def recMC(coinValueList,change):

   minCoins = change

   if change incoinValueList:

     return 1

   else:

      for i in [c for c incoinValueList if c <= change]:

         numCoins = 1 +recMC(coinValueList,change-i)

         if numCoins <minCoins:

            minCoins = numCoins

   return minCoins

 

print(recMC([1,5,10,25],63))

可惜的是,上面算法效率非常之差,实际上,找到6毛3分钱的硬币数量,进行了67,716,925次递归。为了帮助理解,图5显示了一个较小的为了找到2毛6的硬币377次函数调用的过程。

图中,每个节点对一次recMC函数的调用。节点上的标签表示当前求解的找钱数量,箭头上的标签表示减掉的那个硬币。跟踪图形可以得到任意的硬币组合。主要问题在于重复计算太多了,例如图中15分的数值至少有3次计算,每次计算包括52次函数调用,很明显我们很多时间浪费在重复计算上。


减少计算量的关键是记住已经得到的中间结果。一个简单方法是把已经计算出最小值的找钱保存在表里,每次计算之前,先查一下表看看这个结果是否已知。如果已知就直接套用不再计算。下面是优化的算法:

def recDC(coinValueList,change,knownResults):
  minCoins = change
  if change in coinValueList:
     knownResults[change] = 1
     return 1
  elif knownResults[change] > 0:
     return knownResults[change]
  else:
      for i in [c for c in coinValueList if c <= change]:
        numCoins = 1 + recDC(coinValueList, change-i,
                              knownResults)
        if numCoins < minCoins:
            minCoins = numCoins
            knownResults[change] = minCoins
  return minCoins
 
print(recDC([1,5,10,25],63,[0]*64))


注意第6行增加一个测试表中是否包括了计算结果,如果没有,计算并保存到表中。这样优化后,计算6毛3分钱的最小硬币数量,只用了221次调用。

虽然这个结果是正确的,但似乎有点黑客的味道。并且如果查看一下knownResults列表,会发现有太多的洞(0值),事实上上面的算法不能称之为动态规划,只是利用了记忆或缓冲的做法优化了我们程序的性能。

真正的动态规划算法要更加系统化地逼近问题答案。解决方法从一个硬币开始,逐步靠近我们要计算的数值,在中间过程中每个找钱数字我们都得到了所需的最少硬币数量。

我们来研究一下,对于11分的找钱计算最小需要的硬币数量,怎样填表。如图4所示的过程,从1分开始,唯一可能是1个硬币。下一行显示的是1分和2分的情况,当然,2分也只有一个答案就是2个硬币。从第5行开始事情变得有意思起来,我们有2个选择,是5个1分币或1个5分币。哪个方案好?我们查表发现对要找4分钱的情况是4个硬币,加上1个就5个硬币,或者是0个5分币加上1个5分币为1个硬币。因为最小值是1,我们在表中填上1。继续向前到表的末端考虑11分的情况,图5所示为我们要考虑的3个选项。

  1. 1个1分币加上10分找钱的最小硬币数量(1个)
  2. 1个5分币加上6分找钱的最小硬币数量(2个)
  3. 1个10分币加上1分找钱的最小硬币数量(1个)

1和3都给出了最小值2的答案。



下面是找零的程序代码。dpMakeChange有3个参数:可用硬币的列表,找钱的数量,每个找零值所需硬币的最小数量列表。函数计算完成后,minCoin将包括小于找钱的所有找零值所需要的最小硬币数量。

Listing 8


def dpMakeChange(coinValueList,change,minCoins):
   for centsinrange(change+1):
     coinCount = cents
      for jin [cfor cin coinValueListif c<= cents]:
           if minCoins[cents-j]+1< coinCount:
              coinCount = minCoins[cents-j]+1
     minCoins[cents] = coinCount
   return minCoins[change]


注意dpMakeChange不是一个递归函数,虽然我们是从递归开始的。你要明白,虽然你可以写一个递归解法,并不意味着递归就是最好或最有效率的。这个函数的大部分工作是从第4行开始的循环中完成的,这个循环里,我们通过cents值考虑了所有可能的硬币找法,象在上面我们找11分的例子一样,把小于change值的所有最小找法存放在minCoins列表里。


虽然上面的找零算法很好地给出了最小的数量,但是不能用于找零操作,因为没有跟踪用到的零钱。我们可以很容易扩展算法,通过在minCoin表的入口记住最后加入的每个硬币来得到实际找的零钱。只要知道了最后加入的硬币,就可以减去这个硬币值得到上一个表的入口,依此类推直到最开始的第一个硬币。

下面代码显示了dpMakeChange的改进算法,加入一个函数printCoins用来倒查表格来打印每种硬币的使用数量。这里用到了我们解决Lower Elbonia问题时的做法。Main函数前两行给出了找零的数量和硬币种类列表,下面两行创建两个后面要存储结果的列表,coinsUsed是存储找零用到的硬币的列表,coinCount是找零最小硬币数量的列表,这个表里找零值就是表索引。

注意我们打印硬币的时候,是从coinsUsed数组里直接输出的,例如查表63的位置,得到21,然后63-21=42,查找42的位置,再次得到21,最后在21的位置也查到了21,也就是说是3个21分的硬币。


def dpMakeChange(coinValueList,change,minCoins,coinsUsed):
  for cents in range(change+1):
     coinCount = cents
     newCoin = 1
     for j in [c for c in coinValueList if c <= cents]:
            if minCoins[cents-j] + 1 <coinCount:
               coinCount = minCoins[cents-j]+1
               newCoin = j
     minCoins[cents] = coinCount
     coinsUsed[cents] = newCoin
  return minCoins[change]
 
def printCoins(coinsUsed,change):
  coin = change
  while coin > 0:
     thisCoin = coinsUsed[coin]
     print(thisCoin)
     coin = coin - thisCoin
 
def main():
   amnt = 63
   clist = [1,5,10,21,25]
   coinsUsed = [0]*(amnt+1)
   coinCount = [0]*(amnt+1)
 
   print("Making change for",amnt,"requires")
   print(dpMakeChange(clist,amnt,coinCount,coinsUsed),"coins")
   print("They are:")
   printCoins(coinsUsed,amnt)
   print("The used list is as follows:")
   print(coinsUsed)
 
main()



深入Python数据结构与算法分析的课程资源 htmltable {th, td {th {pre {简介:Python是一种广泛应用于多个领域的高级编程语言,以简洁易读著称。本资源集包含了课件PPT和电子图书,系统讲解了Python数据结构与算法分析,包括列表、元组、集合、字典和堆等数据结构,以及排序、搜索、动态规划、回溯法、分治策略、贪心算法和图算法等常用算法。通过这些资源的学习,学习者能够提高编程技能和解决实际问题的能力。 阅读详情

相关推荐

浅谈车联网概述-1

车联网技术目前在车企中应用广泛,车联网通过车载传感器、无线通信等技术,能够将车辆上百的传感器数据上传至云端,当前智能网联车辆可以理解为一个“大号”手机。

Hello, World! 新能源汽车智能网联工程师,分享日常工作思考。 559

详解动态规划算法(Python)

动态规划解题四组成部分 1、确定状态 解动态规划的时候需要一个数组,数组的每个元素F[i],或者F[i,j]代表什么需要明确; 确定状态需要两个意识: 1.1 最后一步 k枚硬币a a a...a,面值加起来应该等于11,最后的硬币是a1.2 子问题 除掉最后一枚硬币,前面的k-1枚硬币加起来应该等于27-a​​​​​​​,因为是最有策略,所以拼出 2、建立状态转移方程 3、初始条件和边界情况 4、计算顺序 ...

skysenlin的专栏 7568

告别死记硬背!用实际案例带你玩转UE5编辑器界面(附场景搭建练习)

本文通过实际案例教学,带你轻松掌握Unreal Engine5编辑器界面的核心功能。从创建基础场景到添加光源和可交互对象,逐步讲解内容浏览器、模式面板、世界大纲等模块的协同工作方式,告别死记硬背的学习模式。附场景搭建练习,助你快速上手UE5开发。

weixin_30566063的博客 729

动态规划(Python)

动态规划学习笔记

1 6050

关于三维全波电磁场仿真软件CST的安装和问题解决

百度网盘链接:https://pan.baidu.com/s/1RgWr8Qau1EzSOlh29SewFQ提取码:fzza这里是2023版本的CST,需要其他版本的uu们可以去官网或者其他人的网盘下载。

weixin_60728441的博客 3606

KEGG两类报错--①No gene can be mapped--②URL ‘https://rest.kegg.jp/link/hsa/pathway‘…

版本问题,重新安装一下clusterProfiler包。网络问题,可以等待之后再试一下(试过不是)(以上可以排除基因不存在的错误因素)

weixin_57699783的博客 2万+

自动驾驶规划 - 5次多项式拟合

自动驾驶运动规划中会用到各种曲线,主要用于生成车辆的轨迹,常见的轨迹生成算法,如贝塞尔曲线,样条曲线,以及apollo EM Planner的五次多项式曲线,城市场景中使用的是分段多项式曲线,在EM Planner和Lattice Planner中思路是,都是先通过动态规划生成点,再用5次多项式生成曲线连接两个点(虽然后面的版本改动很大,至少lattice planner目前还是这个方法)。在这里可以看出5次多项式的作用,就是生成轨迹,这里的轨迹不一定是车行驶的轨迹,

weixin_43673156的博客 7022

Codesys入门-新建工程+任务调用+编译+调试

程序组织单元(Program Organization Unit, POU)由声明区和代码区组成,是用户程序的最小软件单元,它相当于传统编程系统中的块(Block),按功能程序组织单元(POU)可分为函数(FUN)、功能块(FB)、程序(PRG)。:Codesys采用多任务的方式来执行用户程序的“任务”,而每个“任务”分配了不同的执行周期,有些全局变量可能要在不同的POU之间被访问和修改,于是需要对全局变量进行交互同步,也是在任务的“时间对准点”进行的,实例:声明了INT类型,变量名为输入;

刺客 1万+

python 实现动态规划

程序输出了最大价值以及选择的物品索引,使用二维数组 dp 来存储子问题的最优解,其中 dp[i][j] 表示在考虑前 i 个物品,且背包容量为 j 的情况下的最优解。step 3:边缘状态构造好以后,遍历矩阵,补全矩阵中每个位置的dp数组值:如果当前的位置是(i,j),上一步要么是(i−1,j)往下,要么就是(i,j−1)往右,那么取其中较小值与当前位置的值相加就是到当前位置的最小路径和,因此状态转移公式为dp[i][j]=min(dp[i−1][j],dp[i][j−1])+matrix[i][j]

liulanba的博客 1万+

【AlphaFold2】深入浅出,讲解Evoformer|学习笔记

本篇博客是围绕youtube德国博主Kilian Mandon()的《从头实现AlphaFold2:AlphaFold Decoded》的第五期视频讲解和note-book内容写成的笔记,加上了自己的理解和对相关概念的解释。上期我们讲解了AlphaFold2的特征提前的部分【AlphaFold2】Feature extraction:提取特征,为模型输入做准备|Datapipeline讲解。本期,我们将介绍AlphaFold2中最为庞大且最为重要的部分——Evoformer。

Yaoyao2024的博客 2013

Python实现FFT、小波变换和数据压缩

小波变换是一种分析信号的方法,可以分解信号成为多个尺度和频率的分量,从而更好地理解和处理信号。在Python中,我们可以使用pywt库来实现小波变换。在Python中,我们可以使用numpy库中的fft模块来实现FFT。数据压缩是一种将数据表示成更紧凑的形式的方法,可以减少存储空间和传输带宽。综上所述,Python提供了很多方便的工具来实现各种信号处理和数据压缩的方法。本文将介绍Python中如何实现傅里叶变换(FFT)、小波变换以及如何使用它们来进行数据压缩。Python实现FFT、小波变换和数据压缩。

学习使你进步。 692

动态规划详解Python

它通常用于优化问题,其中问题可以被分解成一系列重叠子问题,通过存储并重复使用已经解决过的子问题的解,可以避免重复计算,从而提高算法的效率。问题:有一个数组,求其中两个数x,y,满足x的索引小于y的索引,使得 x-y 最大。例如 arr = [3,7,2,6,4,1,9,8,5], 最大回撤是6,对应的x=7,y=1。例如:arr = [1,5,-10,2,5,-3,2,6,-3,1]. 输出为:12。动态规划算法通常具有较高的时间复杂度,但通过存储已解决的子问题的解,可以大大减少重复计算,提高算法效率。

qq_34184505的博客 6074

Qt Quick/QML入门到精通_专栏demo对应文章目录(目前50个左右demo/长期更新)

自定义图标下拉列表框的效果如下所示:自定义三态按钮的效果如下所示:传送门:53.qt quick-自定义三态按钮、自定义图标下拉列表框_诺谦的博客-优快云博客传送门:59.qt quick-qml调色板(颜色取色器)实现、自定义QQuickStyle样式_诺谦的博客-优快云博客63.qt quick-QML侧边滑动栏(不需要任何图片资源,支持自定义左右方向和大小)_诺谦的博客-优快云博客_qt实现好看侧边栏。...

抵抗时间扭曲,坚持做一件有意义的事 2万+

LeetCode82完全指南:掌握26种算法模板,轻松拿下大厂offer [特殊字符]

想要在大厂技术面试中脱颖而出?LeetCode82项目为你提供了完整的解决方案!这个开源项目汇集了26种核心算法模板,涵盖了数据结构与算法的所有关键知识点,帮助你系统性地提升编程能力和面试竞争力。无论你是算法新手还是有一定经验的开发者,这套模板都能让你快速掌握解题套路,从容应对各类面试挑战。 ## 为什么选择LeetCode82项目? 🤔 LeetCode82项目是一个专门为技术面试准备的算

gitblog_00280的博客 738

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

数据结构与算法必备的 50 个代码实现。

数据结构和算法是程序员的内功心法和基本功。无论是人工智能还是其它计算机科学领域,掌握扎实的数据结构和算法知识,往往会助力不少!今天给大家推荐一份不错的数据结构与算法资源。特点是:全代码实现!这份资源的作者王争老师是前 Google 工程师,5 万+人跟着学的《数据结构和算法之美》专栏作者。他总结了程序员必备的 50 个数据结构与算法,以及相应的代码实现。开源地址为:https...

weixin_33859504的博客 5805

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【第一天】零基础入门刷题Python-算法篇-数据结构与算法的介绍(持续更新)

第一天Python数据结构与算法的详细介绍提示:以下是本篇文章正文内容,下面案例可供参考数据结构:是指计算机中存储和组织数据的方式。不同的数据结构适用于不同的应用场景,选择合适的数据结构可以显著提高程序的运行效率。空间占用尽量少,以节省计算机内存。数据操作尽可能快速,涵盖数据访问、添加、删除、更新等。提供简洁的数据表示和逻辑信息,以便算法高效运行。算法:是指完成特定任务的一系列步骤或规则,它在有限时间内解决特定问题的一组指令或操作步骤。问题是明确的,包含清晰的输入和输出定义。

2301_78806917的博客 4160

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

RKNN-Toolkit2 实战:RV1106/RV1103 平台 mobilenet_v1 分类 Demo 的交叉编译、部署与零拷贝推理详解

本文以 rknn-toolkit2 仓库中 `rknpu2/examples/RV1106_RV1103/rknn_mobilenet_demo` 示例为核心,完整讲解基于 RKNN 的 MobileNet V1 图像分类模型如何在 Rockchip RV1106、RV1106B、RV1103、RV1103B 这四款轻量级 NPU 平台上完成交叉编译、部署与运行。读完本文,你将掌握 `build-

gitblog_00339的博客 1001

北京大学《数据结构与算法(Python版)》笔记(上册)

北京大学陈斌老师课程详细笔记

Fransonia的博客 1569

数据结构与算法(LeetCode高频300题 Python3实现)

文章目录1、课程:Introduction2、课程:数组和动态数组3、课程:递归4、课程:搜索与排序5、课程:二分搜索6、课程:分治法(上)7、课程:分治法(下)8、课程:链表(上)9、课程:链表(下)10、课程:堆栈和队列(上)11、课程:堆栈和队列(下)12、课程:哈希表(上)13、课程:哈希表(下)14、课程:树(上)15、课程:树(下)16、课程:堆(上)17、课程:堆(下)18、课程:图...

算法探索之路 5250

Python中的数据结构与算法:提升编程效率的核心技巧

本文介绍了Python中常用的数据结构(列表、元组、集合、字典、队列/堆栈)及其特性,包括时间复杂度和使用场景。同时讲解了常见算法如排序(Timsort)、二分查找和动态规划的实现与应用,强调合理选择数据结构和算法对提升程序效率的重要性。掌握这些核心概念能帮助开发者编写更高效、优雅的代码。

2501_94122568的博客 901

leetcode python3 简单题168. Excel Sheet Column Title

1.编辑器 我使用的是win10+vscode+leetcode+python3 环境配置参见我的博客: 链接 2.第一百六十八题 (1)题目 英文: Given a positive integer, return its corresponding column title as appear in an Excel sheet. 中文: 给定一个正整数,返回它在 Excel 表中相对应的列名...

从此做一个俗人 312

数据结构与算法(Python版)——(3)递归(下)用实例介绍动态规划算法

目录1、分治策略 1、分治策略

Ma Sizhou 734

数据结构与算法必备的 50 个代码实现

点击上方“AI有道”,选择“置顶”公众号重磅干货,第一时间送达数据结构和算法是程序员的内功心法和基本功。无论是人工智能还是其它计算机科学领域,掌握扎实的数据结构和算法知识...

红色石头的专栏 1996

数据结构与算法Python版(code&note)

1.电影推荐超时空连接The.Imitation.Game.2014(关于图灵的)2.2参考​​​​​​​​​​​​​​Problem Solving with Algorithms and Data Structures using Python — Problem Solving with Algorithms and Data Structures (runestone.academy)数据结构与算法Python版 自学课程指南 - 哔哩哔哩 (bilibili.com)

m0_73613426的博客 929

python数据结构和算法

线性 数据结构 以 有序的方式保存它们的数据。栈是维持 LIFO,后进先出,排序的简单数据结构。栈的基本操作是 push,pop和 isEmpty。队列是维护 FIFO(先进先出)排序的简单数据结构。队列的基本操作是 enqueue,dequeue 和 isEmpty。前缀,中缀 和 后缀 都是写表达式的方法。栈 对于设计计算解析表达式算法非常有用。栈可以提供 反转特性。队列可以帮助 构建定时仿真。模拟使用 随机数生成器 来创建真实情况,并帮助我们回答“假设”类型的问题。

实践出真理,接毕设/课设项目开发指导 835
上一篇: python数据结构与算法 25 探索迷宫
下一篇: 程序员成长攻略
杀了这个男孩
博客等级 码龄18年 149粉丝 38原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值