找零兑换问题:递归解法

引言

用递归解决找零兑换问题,首先先要明确递归三定律
1.最小规模问题(基本结束条件)
2.减小问题规模(向结束条件演进)
3.解决减小了规模的相同问题(调用自身)

应用到实际找零兑换的问题上,首先明确最小规模问题:需要兑换的找零,其面值正好等于某种硬币。如我们需要找零25分,刚好有25分面值的硬币,这里就只需要1个硬币就可完成找零。
找零兑换问题:递归解法_第1张图片
其次是减小问题的规模:对每种硬币的面值分别尝试。
如美元硬币体系:找零减去1分(penny)、5分(nikel)、10分(dime)、25分(quarter)后求兑换硬币的最少数量(递归调用自身)
选则上述减小规模次数最小的方案完成找零
找零兑换问题:递归解法_第2张图片

代码如下

import time

def recMC(coinValueList, change):
    mincoin = change
    #最小规模问题,如果找零刚好有面值相等的硬币即返回1
    if change in coinValueList:
        return 1
    else:
        #减小问题规模,将每种情况都试完,选择找零需要的最小硬币数
        for i in [c for c in coinValueList if c < change]:
            numcoin = 1 + recMC(coinValueList, change-i)
            if numcoin < mincoin:
                mincoin = numcoin
    return mincoin

t1=time.process_time()
print(recMC([1,5,10,25], 63))
t2=time.process_time()
print('time:',t2-t1)

在这里插入图片描述
该方法虽然能解决问题,但是效率极其低下,对63分硬币兑换的问题,需要进行67716925次递归调用。

算法改进

前面算法的弊端在于计算的重复次数太多,对这个递归算法进行改进的关键就在于消除重复计算,我们可以用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过,如果计算过了就直接返回

改进代码

import time

def recDC(coinValueList, change, coinList):
    mincoin = change
    #最小规模问题,如果找零刚好有面值相等的硬币即返回1
    if change in coinValueList:
        coinList[change] = mincoin #记录最优解
        return 1
    elif coinList[change] > 1:
        return coinList[change] #查表成功直接用最优解
    else:
        #减小问题规模,将每种情况都试完,选择找零需要的最小硬币数
        for i in [c for c in coinValueList if c < change]:
            numcoin = 1 + recDC(coinValueList, change-i, coinList)
            if numcoin < mincoin:
                mincoin = numcoin
                #找到最优解记录到表中
                coinList[change] = mincoin
    return mincoin

t1=time.process_time()
print(recDC([1,5,10,25], 63, [0]*64))
t2=time.process_time()
print('time:%.6f'%(t2-t1))

在这里插入图片描述
由结果可以看出,优化后的递归算法对于63分兑换硬币的问题,仅仅需要221次递归调用,是改进前的30万分之一,运行时间几乎可以忽略不计。

你可能感兴趣的:(找零兑换问题:递归解法)