面试题 08.11. 硬币
September 12, 2026 · View on GitHub
题目描述
硬币。给定数量不限的硬币,币值为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
解法
方法一:动态规划
思考
用 $25,10,5,1n$,顺序不记。按硬币个数三重循环可行,但与完全背包同一结构。
令 为前 种币凑 的方案数。完全背包转移 (当 )。
硬币种类极少,二维表 $5\times(n+1)f[0][0]=1 作为空凑法。对 \1+7$ 取模。
我们定义 表示只使用前 种硬币的情况下,凑成总金额为 的方案数。初始时 ,其余元素都为 $0f[4][n]$。
考虑 ,我们可以枚举使用的第 种硬币的个数 ,其中 $0 \leq k \leq j / c_if[i][j]f[i−1][j−k \times c_i]k 可以从 \0$ 开始取。即状态转移方程如下:
不妨令 ,那么上面的状态转移方程可以写成:
将二式代入一式,得到:
最后的答案即为 。
时间复杂度 ,空间复杂度 ,其中 为硬币的种类数。
Python3
class Solution:
def waysToChange(self, n: int) -> int:
mod = 10**9 + 7
coins = [25, 10, 5, 1]
f = [[0] * (n + 1) for _ in range(5)]
f[0][0] = 1
for i, c in enumerate(coins, 1):
for j in range(n + 1):
f[i][j] = f[i - 1][j]
if j >= c:
f[i][j] = (f[i][j] + f[i][j - c]) % mod
return f[-1][n]
Java
class Solution {
public int waysToChange(int n) {
final int mod = (int) 1e9 + 7;
int[] coins = {25, 10, 5, 1};
int[][] f = new int[5][n + 1];
f[0][0] = 1;
for (int i = 1; i <= 4; ++i) {
for (int j = 0; j <= n; ++j) {
f[i][j] = f[i - 1][j];
if (j >= coins[i - 1]) {
f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod;
}
}
}
return f[4][n];
}
}
C++
class Solution {
public:
int waysToChange(int n) {
const int mod = 1e9 + 7;
vector<int> coins = {25, 10, 5, 1};
int f[5][n + 1];
memset(f, 0, sizeof(f));
f[0][0] = 1;
for (int i = 1; i <= 4; ++i) {
for (int j = 0; j <= n; ++j) {
f[i][j] = f[i - 1][j];
if (j >= coins[i - 1]) {
f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod;
}
}
}
return f[4][n];
}
};
Go
func waysToChange(n int) int {
const mod int = 1e9 + 7
coins := []int{25, 10, 5, 1}
f := make([][]int, 5)
for i := range f {
f[i] = make([]int, n+1)
}
f[0][0] = 1
for i := 1; i <= 4; i++ {
for j := 0; j <= n; j++ {
f[i][j] = f[i-1][j]
if j >= coins[i-1] {
f[i][j] = (f[i][j] + f[i][j-coins[i-1]]) % mod
}
}
}
return f[4][n]
}
TypeScript
function waysToChange(n: number): number {
const mod = 10 ** 9 + 7;
const coins: number[] = [25, 10, 5, 1];
const f: number[][] = Array.from({ length: 5 }, () => Array(n + 1).fill(0));
f[0][0] = 1;
for (let i = 1; i <= 4; ++i) {
for (let j = 0; j <= n; ++j) {
f[i][j] = f[i - 1][j];
if (j >= coins[i - 1]) {
f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod;
}
}
}
return f[4][n];
}
Swift
class Solution {
func waysToChange(_ n: Int) -> Int {
let mod = Int(1e9 + 7)
let coins = [25, 10, 5, 1]
var f = Array(repeating: Array(repeating: 0, count: n + 1), count: 5)
f[0][0] = 1
for i in 1...4 {
for j in 0...n {
f[i][j] = f[i - 1][j]
if j >= coins[i - 1] {
f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod
}
}
}
return f[4][n]
}
}
方法二:动态规划(空间优化)
思考
第 行只读第 行与同行更小的 ,第一维可以压掉。
一维滚动数组按 从小到大更新,空间降为 ,转移式不变。
我们注意到, 的计算只与 有关,因此我们可以去掉第一维,将空间复杂度优化到 。
Python3
class Solution:
def waysToChange(self, n: int) -> int:
mod = 10**9 + 7
coins = [25, 10, 5, 1]
f = [1] + [0] * n
for c in coins:
for j in range(c, n + 1):
f[j] = (f[j] + f[j - c]) % mod
return f[n]
Java
class Solution {
public int waysToChange(int n) {
final int mod = (int) 1e9 + 7;
int[] coins = {25, 10, 5, 1};
int[] f = new int[n + 1];
f[0] = 1;
for (int c : coins) {
for (int j = c; j <= n; ++j) {
f[j] = (f[j] + f[j - c]) % mod;
}
}
return f[n];
}
}
C++
class Solution {
public:
int waysToChange(int n) {
const int mod = 1e9 + 7;
vector<int> coins = {25, 10, 5, 1};
int f[n + 1];
memset(f, 0, sizeof(f));
f[0] = 1;
for (int c : coins) {
for (int j = c; j <= n; ++j) {
f[j] = (f[j] + f[j - c]) % mod;
}
}
return f[n];
}
};
Go
func waysToChange(n int) int {
const mod int = 1e9 + 7
coins := []int{25, 10, 5, 1}
f := make([]int, n+1)
f[0] = 1
for _, c := range coins {
for j := c; j <= n; j++ {
f[j] = (f[j] + f[j-c]) % mod
}
}
return f[n]
}
TypeScript
function waysToChange(n: number): number {
const mod = 10 ** 9 + 7;
const coins: number[] = [25, 10, 5, 1];
const f: number[] = new Array(n + 1).fill(0);
f[0] = 1;
for (const c of coins) {
for (let i = c; i <= n; ++i) {
f[i] = (f[i] + f[i - c]) % mod;
}
}
return f[n];
}