题目:有半美元、四分之一美元、10美分、5美分和1美分的硬币,将1美元换成零钱,一共有多少种不同方式?
思路:
首先我们把1美元变成100美分,半美元变成50美分,四分之一美元变成25美分。然后从硬币的最大面额
50美分开始:
100余额的所有换法 = 采用50美分的所有换法 + 不采用50美分的所有换法
那么,我们首先来看采用50美分的换法,既然采用了50美分,那么至少得用一个,换句话说,
我们就可以把问题转换为计算余额为100-50=50美分的所有换法:
100余额采用50美分的所有换法 = 50余额的所有换法
而:
50余额的所有换法 = 采用50美分的所有换法 + 不采用50美分的所有换法
这儿就递归到了采用50美分的所有换法,我们再次减去50美分时,余额为0,就代表有了一种换法,应该返回1;
这时,我们再返回余额为50时,不采用50美分的所有换法上面,那么,我们会取用除了50之外的最大面额25:
50余额不采用50美分的所有换法 = 采用25美分的所有换法 + 不采用25美分的所有换法
看着是不是很眼熟了呢?很明显,我们又可以进行递归了。
50余额采用25美分的所有换法 = 25余额的所有换法
而:
25余额的所有换法 = 采用25美分的所有换法 + 不采用25美分的所有换法
如上所述,我们可以发现,递归终止的条件有两个,一个是余额,另一个是硬币的数量。如果余额为0,则代表
有一种换法,返回1,余额为负,则代表这种换法不可行,返回0。硬币的数量为什么是递归的终止条件呢,因为
我们会不断根据当前余额去取在硬币集合中离当前余额面值最近的硬币,如果没有更多地硬币了,那么当然应该
终止递归。
程序如下:
user> (defn lq [x] ;定义硬币 (cond (= 1 x) 1 (= 2 x) 5 (= 3 x) 10 (= 4 x) 25 (= 5 x) 50)) user> (defn clq [a x] ;定义递归算法 (cond (zero? a) 1 ;如果余额为0,则说明有一种换法 (or (neg? a) (zero? x)) 0 ;如果余额为负或者已经取完硬币,则说明没有换法 :else (+ (clq a (dec x)) (clq (- a (lq x)) x)))) user> (clq 100 5) ;两个参数为要换的金额和最大硬币数量 292