我们有25分,10分,5分和1分的硬币无限个。写一个函数计算组成n分的方式有几种?
一开始,我觉得使用递归不断地累加四种币值的硬币,当累加到n分,组成方式就加1。 最后就能得到一共有多少种组合方式,听起来挺正确的,然后写了以下代码:
但,这是错误的。问题出在哪?有序与无序的区别!这个函数计算出来的组合是有序的,
也就是它会认为15和51是不一样的,导致计算出的组合里有大量是重复的。
那要怎么避免这个问题?15和51虽然会被视为不一样,但如果它们是排好序的,
比如都按从大到小排序,那么就都是51了,这时就不会重复累计组合数量。
可是我们总不能求出答案来后再搞个排序吧,多费劲。这时我们就可以在递归上做个手脚,
让它在计算的过程中就按照从大到小的币值来组合。比如,
10分的,下一次可以取的币值就只有1051了;这样一来,就能保证,同样的组合,
我只累计了一次,改造后的代码如下:
```cpp
有个全局变量总觉得看起来不好看,于是我们可以把这个全局变量去掉, 让函数来返回这个组合数目,代码如下:
也是从币值大的硬币开始,每次取i个(i乘以币值要小于等于n), 然后接着去取币值比它小的硬币,这时就是它的一个子问题了,递归调用。 具体来怎么来理解这个事呢?这样,比如我要凑100分,那我先从25分开始, 我先取0个25分,然后递归调用去凑100分;再然后我取1个25分,然后递归调用去凑100-25 =75分;接着我取2个25分,递归调用去凑100-25*2=50分……这些取了若干个 25分然后再去递归调用,取的就是10分了。一直这样操作下去,我们就会得到, 由若干个25,若干个10分,若干个5分和若干个1分组成的100分,而且, 这里面每种币值的数量都可以为0。