現金找零方式的總數(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];得出的結果是同樣的,也就是說零錢的隨便怎麼排序均可以。

相關文章
相關標籤/搜索