题目:
硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)
示例:
输入: 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
题解:
动态规划解法:完全背包问题
完全背包问题即不限定硬币的个数地去组合硬币达到指定的值。 这道题为求组合成指定数额有几种情况,我们设置 dp 数组: dp[k] 为组成k面额的硬币情况数。
这里的 dp[0] 的含义是:组成0的硬币种类数为 1,(没有硬币也是一种情况)
可以用于边界判断,作为完美能被一个硬币表示的情况为 1。即:
while k - coin == 0 :
dp[k] += dp[k - coin];
=>
dp[k] += dp[0];
错误解!!!!:
class Solution {
public int waysToChange(int n) {
int[] dp = new int[n + 1];
int[] coins = new int[]{1,5,10,25};
//刚好可以用一个硬币凑成的情况,是一种情况
// while i == coin :
//dp[i] = dp[i - coin] => dp[0]
dp[0] = 1;
/**
* dp方程:dp[i] += dp[i - coin];
*/
for(int i = 1; i <= n; i++) {
for(int coin: coins) {
if(i - coin < 0) break;
dp[i] = (dp[i] + dp[i - coin]) % 1000000007;
}
}
return dp[n];
}
}
这是因为硬币的顺序是与题解无关的,但是却被多算了一遍,具体情况:
前面5种情况数:dp[1,5] = [1,1,1,1,2];
coin = 1:
dp[6] += (dp[6 - coin] => dp[5] => 2);
即拿到coin(1)的情况有两种 :
coin(1,1,1,1,1) + coin(1);
coin(5) + coin(1);
coin = 5:
dp[6] += (dp[6 - coin] => dp[1] => 1);
即拿到coin(5)的情况有一种:
coin(1) + coin(5);
正确解qaq:
class Solution {
public int waysToChange(int n) {
int[] dp = new int[n + 1];
int[] coins = new int[]{1,5,10,25};
//刚好可以用一个硬币凑成的情况,是一种情况
// while i == coin :
//dp[i] = dp[i - coin] => dp[0]
dp[0] = 1;
/**
* dp方程:dp[i] += dp[i - coin];
*/
for(int coin : coins) {
for(int i = coin; i <= n; i++) {
dp[i] = (dp[i] + dp[i - coin]) % 1000000007;
}
}
return dp[n];
}
}
这种情况要把硬币的排序影响情况去除掉:
coin = 1:
前面5种情况数:dp[1,5] = [1,1,1,1,1];
dp[6] += (dp[6 - coin] => dp[5] => 1);
即拿到coin(1)的情况有一种 :
coin(1,1,1,1,1) + coin(1);
coin = 5:
前面5种情况数:dp[1,5] = [1,1,1,1,2];
dp[6] += (dp[6 - coin] => dp[1] => 1);
即拿到coin(5)的情况有一种:
coin(1) + coin(5);
心得:
dp算法是真的好用!qaq