每日leetcode-面试题-08-11

面试题 08.11. 硬币

硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

示例1:

输入: n = 5
输出:2
解释: 有两种方式可以凑成总金额:
5=5
5=1+1+1+1+1

示例2:

输入: n = 10
输出:4
解释: 有四种方式可以凑成总金额:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1

说明:

注意:

你可以假设:

  • 0 <= n (总金额) <= 1000000

解法

这个和官方题解里面的方法一类似,但是有一点差别。

官方题解里面,最后得到的是:

$$f(i,v)=f(i−1,v)+f(i,v−c_i)$$

举例来说,如果我想要用4种硬币(分别是1、5、10、25)来凑成100分,那我可以先算出来用3种硬币(1、5、10)凑成100分的方法,再算出来用4种硬币(1、5、10、25)凑成75分的方法数,把他们加起来。

这样的好处是,我们可以只用前面$i-1$的数据算出来$i$的数据,就不用存所有行了。

我这里的解法稍微差一些,是记录了四个数组,分别表示:最大用了1分、最大用了5分、最大用了10分、最大用了25分的前提下的种类数。

如果我想要用4种硬币(分别是1、5、10、25)来凑成100分,那我可以先算出来:

  • 用最大为25的硬币(也就是说,用了4种硬币(1、5、10、25)并且必须有25)凑成75分的方法;
  • 用最大为10的硬币(也就是说,用了3种硬币(1、5、10)并且必须有10)凑成75分的方法;
  • 用最大为5的硬币(也就是说,用了2种硬币(1、5)并且必须有5)凑成75分的方法;
  • 用最大为1的硬币(也就是说,用了1种硬币(1)并且必须有1)凑成75分的方法。

最后加起来就是总的方法数。

不如csx大佬的官方题解,但是也是正确的做法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int waysToChange(int n) {
if (n == 0) {
return 1;
}
vector<int> dp_max_1(n + 1, 1);
vector<int> dp_max_5(n + 1, 0); // 必须有至少一个5
vector<int> dp_max_10(n + 1, 0);
vector<int> dp_max_25(n + 1, 0);
for (int i = 5; i <= n; i++) {
dp_max_5[i] = (dp_max_1[i - 5] + dp_max_5[i - 5]) % 1000000007; // use one 5, will get dp_max_1[i - 5]; use two 5s, dp_max_5[i - 5]
}
for (int i = 10; i <= n; i++) {
dp_max_10[i] = (dp_max_1[i - 10] + dp_max_5[i - 10] + dp_max_10[i - 10]) % 1000000007;
}
for (int i = 25; i <= n; i++) {
dp_max_25[i] = (dp_max_1[i - 25] + dp_max_5[i - 25] + dp_max_10[i - 25] + dp_max_25[i - 25]) % 1000000007;
}
return (dp_max_1[n] + dp_max_5[n] + dp_max_10[n] + dp_max_25[n]) % 1000000007;
}
};