技术标签: python换零钱
比如:顾客购物买37元东西,给了100元,要找63元,那最少数量就是1张50元,1张10元,3张1元,一共4张。
方法一: 贪心策略
解决这个问题,最直观的就是使用贪心策略。我们会从最大面值的钱开始,用最多的数量。有余额再到下一个最大面值,还用最多的数量,一直到1元为止。
def chage_give(coins_list, change):
solutions = []
s_list = sorted(coins_list, reverse=True)
for coin in s_list:
coins_num = change // coin
solutions += [coin,] * coins_num
change = change - coin * coins_num
if coins_num < 0:
break
return len(solutions)
if __name__ == "__main__":
print(chage_give([1, 5, 10, 20, 50, 100], 63))
运行程序,输出打印结果:
>>> 5
贪心策略在人民币的体系下表现还好,但是如果当存在有21元的面值,贪心策略就会失效。因为63元的最优解是3个面值21元。
方法二:递归调用的方式求解
既然贪心策略在特殊的面值下会失效,那我们用递归解决这个问题吧。
递归的三个首先条件,我们先确定基本结束条件:剩余需要兑换的零钱正好等于某面值。例如找零10元,答案就是1张10元。
其次是缩小问题的规模:
找零减去 1元 后, 求兑换零钱的最少数量(递归调用自身);
找零减去 5元 后, 求兑换零钱的最少数量;
找零减去 10元后, 求兑换零钱的最少数量;
找零减去 20元后, 求兑换零钱的最少数量;
找零减去 50元后, 求兑换零钱的最少数量;
上述 5项 中选择最小的一个
def change_give_recursion(coins_list, change):
min_coins = change
# 当要兑换的零钱的值正好等于面值列表中其中一项,就直接返回 1
if change in coins_list:
return 1
else:
# 对各种面值都试用递归调用自身,但选择数量最小的一个。
for i in [ c for c in coins_list if c < change]:
coin_num = 1 + change_give_recursion(coins_list, change - i)
if coin_num < min_coins:
min_coins = coin_num
return min_coins
if __name__ == "__main__":
print(change_give_recursion([1, 5, 10, 20, 50, 100], 63))
运行程序,输出打印结果:
>>> 5
上面递归解法虽然能解决问题,但最大的问题是:非常低效!例如对63元的兑换问题需要进行6千多万的递归调用,有太多的重复计算。所以优化这个算法,我们需要消除重复的计算。
我们可以用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过。这个算法的中间结果就是部分找零的最优解,在递归调用之前先查找表中是否已有部分找零的最优解,如果有,直接返回最优解而不进行递归调用,如果没有,才进行递归调用。
既然存在问题,我们就要做改进,改进后如下:
def change_give_recursion(coins_list, change, known_result):
min_coins = change
if change in coins_list:
# 如果兑换的零钱正好等于其中一个币值,就先将这个结果记录下来
known_result[change] = 1
return 1
elif known_result[change] > 0: # 如果已经存在这个零钱值的结果记录就直接返回
return known_result[change]
else:
for i in [ c for c in coins_list if c < change]:
coin_num = 1 + change_give_recursion(coins_list, change - i, known_result)
if coin_num < min_coins:
min_coins = coin_num
# 将得到的结果保存下来,后面调用是供之后检查
known_result[change] = min_coins
return min_coins
if __name__ == "__main__":
print(change_give_recursion([1, 5, 10, 20, 50, 100], 63, [0] * 64))
改进后的解法,极大的减少了递归调用次数。对63元的兑换问题仅需要进行221次的递归调用,是改进前的三十万分之一。这种中间结果记录的方法叫做“memoization”(记忆化/函数值缓冲)技术,提高了递归解法的性能,这种方法的应用如缓冲。
方法三:动态规划解法
动态规划(Dynamic programming,简称DP)主要用来解决一些希望找到问题最优解的优化问题
找零兑换的动态规划算法从最简单的“1元钱找零”的最优解开始,逐步递加上去,直到我们需要的找零数。在找零递加的过程中,设法保持每一分钱的递加都是最优解,一直加到求解找零数,自然得到最优解。
递加的过程能保持最优解的关键是,其依赖于更少钱数最优解的计算,而更少钱数的最优解已经得到了。问题的最优解包含了更小规模子问题的最优解,这是一个最优化问题能够用动态规划策略解决的必要条件。
计算11分钱的兑换法,我们做如下几步:
1、减去1分钱,剩下10分钱查表最优解是1
2、然后减去5分钱,剩下6分钱查表最优解是2
3、最后减去10分钱,剩下1分钱查表最优解是1
通过上述最小值得到最优解:2个硬币
def change_give_dynamic(coins_list, change, min_coins):
for cents in range(1, change + 1):
coins_count = cents
for j in [c for c in coins_list if c < cents]:
if min_coins[cents - j] + 1 < coins_count:
coins_count = min_coins[cents - j] + 1
min_coins[cents] = coins_count
return min_coins[change]
if __name__ == "__main__":
print(change_give_dynamic([1, 5, 10, 20, 50, 100], 63, [0] * 64))
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法