现金找零方式的总数(sicp)

问题:现有现金a,而且有n种面额的零钱,问,共有多少种找零方式。
问题细化:现有现金1元,而且有50分,25分,10分,5分,1分五种面额,用这5种零钱组成1元,共有多少种方式?rest


若是把n种零钱按照某种顺序排列(如50分,25分,10分,5分,1分,不必定升序或降序,也能够乱序),那么问题能够转化为:
现金a用除第一种零钱以外其余面额的找零方式数目
加上
现金a-d用全部面额的找零方式数目,其中d为第一种零钱的面额code

为何?什么逻辑?有点晕,看不懂?不要紧接着往下看。排序

上面的逻辑等同于
使用第一种零钱的次数为0次,现金a找零方式数目
加上
使用第一种零钱的次数为>=1次,现金a找零方式数目
若是减去1个第一种零钱,那么等价于"使用第一种零钱的次数为>=0次,现金a-d找零方式数目",亦即"现金a-d用全部面额的找零方式数目,其中d为第一种零钱的面额"io


弄明白上面的逻辑,就看例子吧:以50分,25分,10分,5分,1分为序列,现金额度为1元,则找零方式总数
等于console

1元彻底不用50分 + 50分用50,25,10,5,1分//如今第一种零钱为50分

等于function

1元彻底不用50分 + (50分彻底不用50分 + 0分用50,25,10,5,1分)//如今第一种零钱为50分

等于循环

1元用25,10,5,1分 + 50分用25,10,5,1分
//"彻底不用50分"等价于"用25,10,5,1分",“0分用50,25,10,5,1分”是0

等于co

(1元彻底不用25分 + 75分用25,10,5,1分)// 如今硬币总数只有4种,第一种是25分
+
(50分彻底不用25分 + 25分用25,10,5,1分)// 如今硬币总数只有4种,第一种是25分

等于return

(1元彻底不用25分 + (75分彻底不用25分 + 50分用25,10,5,1分))// 如今硬币总数只有4种,第一种是25分
+
(50分彻底不用25分 + (25分彻底不用25分 + 0分用25,10,5,1分))// 如今硬币总数只有4种,第一种是25分

。。。。一直循环下去const


代码实现(js)

const kindsOfCoins = [1, 5, 10, 25, 50];

/**
 * 若是amount正好为0
 * 现金amount,用kinds种硬币的找零方式总数,
 * 等于现金amount,用除了第一种硬币以外其余硬币的找零方式总数 + 现金amount - d用全部硬币的找零方式总数(d为第一种硬币的面值)
 * amount为0,说明前一步amount-firstCoins正好为0,好比25-25,是1种找零方式,return 1
 * amount<0,说明前一步amount-firstCoins相似于10-25,不是找零方式,return 0
 * kinds===0,说明没有找零的硬币了,return 0
 * 
 * @param amount 总金额
 * @param kinds  硬币种类数
 * @returns {*}
 */
function countChange(amount, kinds) {
    const restKindsOfCoins = kindsOfCoins.slice(0, kinds);
    const firstCoins = restKindsOfCoins[kinds - 1];
    if (amount === 0) return 1;
    if (amount < 0) return 0;
    if (kinds === 0) return 0;
    return countChange(amount, kinds - 1) + countChange(amount - firstCoins, kinds);
}

console.log(countChange(100, 5));// 292

注意,若是const kindsOfCoins = [1, 5, 10, 25, 50];改成const kindsOfCoins = [50, 10, 5, 1, 25];得出的结果是同样的,也就是说零钱的随便怎么排序均可以。

相关文章
相关标签/搜索