硬币找零问题几种不同的实现方式(使用Python实现)
问题描述
??假设你为一家自动售货机厂家编程序,自动售货机要每次找给顾客最少数量硬币;假设某次顾客投进$1纸币,买了?37的东西,要找?63,那么最少数量就是:2个quarter(?25)、1个dime(?10)和3个penny(?1),一共6个.
??分别使用贪心算法,递归,以及递归的优化版本:递归 + 备忘录技术,与动态规划四种解法
?? 问题抽象: coin_list = [1,10,25,100]. coin = 63. 在所给定coin_list等于coin最少个数.(63的最优组合是25 25 10 1 1 1.一共6个)
解法一:贪心算法
def get_min_coins(money_value): # 贪心版本 ‘‘‘ 贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。 也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。 ‘‘‘ return_list = [] money_coins = [1,5,10,25,100] # 不兼容爱尔波尼亚的21分硬币.其实63的最优解应该是三个21的硬币.贪心算法的局限性 money_coins_sorted = sorted(money_coins,reverse=True) for current_value in money_coins_sorted: len_current_value = money_value // current_value return_list += [current_value] * len_current_value money_value = money_value - current_value*len_current_value ‘‘‘ 第一次: len_current_value == 2 , return_list = [25,25] , money_value == 13 第二次: ... 第三次: ... 第四次: ... ‘‘‘ if money_value <=0: # 截至条件 break return return_list #print(get_min_coins(63))
解法二:递归求解
def recMC(coin_value_list,money_value): # 使用递归求得最优解 ‘‘‘ 递归三条件: 不断缩小自身规模 不断调用自身 有结束条件 其中,递归是自顶向下进行计算的. ‘‘‘ min_len = money_value if money_value in coin_value_list: # 递归结束条件 return 1 else: for current_value in [c for c in coin_value_list if c < money_value]: now_len = 1 + recMC(coin_value_list,money_value-current_value) # 调用自身,且缩小规模 if now_len < min_len: min_len = now_len return min_len # print(recMC([1,5,10,25], 63)) # 这个程序执行的太慢了.一共需要执行67,716,925次.
解法三:递归优化:备忘录技术
def recDc(coin_value_list,money_value,know_results): # 递归改进版本 ‘‘‘ 递归改进的关键是消除重复计算.其中有一种技术是备忘录技术. 可以用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过 在递归调用之前,先查找表中是否已有部分找零的最优解如果有, 直接返回最优解而不进行递归调用如果没有,才进行递归调用 ‘‘‘ min_len = money_value print(know_results) if money_value in coin_value_list: return 1 elif know_results[money_value] != 0: return know_results[money_value] else: for i in [c for c in coin_value_list if c < money_value]: now_len = 1 + recDc(coin_value_list,money_value-i,know_results) if now_len < min_len: min_len = now_len know_results[money_value] = now_len print(know_results) return min_len # print(recDc([1,5,10,25],63,[0]*64))
解法四:动态规划
def dpMakeChange (coinValueList,change,minCoins): # 动态规划解法 ‘‘‘ 动态规划:其所求的最优解是由子问题的最优解构成的. 动态规划是自底向上的计算. 在找零递加的过程中,设法保持每一分钱的递加都是最优解,一直加到求解找零钱 数,自然得到最优解 ‘‘‘ for coin in range(1,change+1): min_len = coin for i in [ c for c in coinValueList if c <=coin]: if minCoins[coin-i] + 1 < min_len: min_len = minCoins[coin-i]+1 minCoins[coin] = min_len return minCoins[change] # print(dpMakeChange([1,5,10,25],63,[0]*64))
解法四扩展:动态规划扩展
def dp_make_change(coin_value_list,money_value,minCOins,coins_record):# coins_record记录每一个最优解所添加的硬币.用于返回最优硬币 ‘‘‘ ‘‘‘ for coin in range(1,money_value+1): min_len = coin new_add_coin =1 for i in [c for c in coin_value_list if c <= coin]: if minCOins[coin-i] + 1 < min_len: min_len = minCOins[coin-i] + 1 new_add_coin = i minCOins[coin] = min_len coins_record[coin] = new_add_coin # print(coins_record) return minCOins[money_value] def print_coins(cions_record,how_much_money): ‘‘‘ 在得到最后的解后,减去选择的硬币币值,回溯到表格之前的部分找零, 就能逐步得到每一步所选择的硬币币值 ‘‘‘ rev_cions = [] while how_much_money>0: how_much_money = how_much_money - cions_record[how_much_money] rev_cions.append(cions_record[how_much_money]) return rev_cions # some_money = 63 # cions_record = [0]*64 # print(dp_make_change([1,5,10,25],some_money,[0]*64,cions_record)) # print(print_coins(cions_record,some_money))
参考
相关推荐
steeven 2020-11-10
Tips 2020-10-14
nongfusanquan0 2020-08-18
yedaoxiaodi 2020-07-26
清溪算法君老号 2020-06-27
pengkingli 2020-06-25
yishujixiaoxiao 2020-06-25
清溪算法 2020-06-21
RememberMePlease 2020-06-17
nurvnurv 2020-06-05
SystemArchitect 2020-06-02
码墨 2020-05-29
清溪算法 2020-05-27
choupiaoyi 2020-05-27
清溪算法 2020-05-25
bluewelkin 2020-05-19
dbhllnr 2020-05-15
steeven 2020-05-09
baike 2020-05-09