面试题 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题
凑硬币,动态规划;
设dp[i][j]表示用前i个硬币凑j块钱的方法数;
初始化
i=0,即没有硬币,凑每一个j都是0种;
i=1,即第一个硬币,凑0块钱都是一种(不用凑);
for(int i=1;i<5;i++){
dp[i][0]=1;
for(int j=1;j<=n;j++)
if(j>=coins[i])
dp[i][j]=dp[i][j-coins[i]]+dp[i-1][j];
else
dp[i][j]=dp[i-1][j];
开始递推,用第i个数 dp[i][j-coins[i]], 不用第i个数dp[i-1][j];
若j<coins[i]的大小,则肯定不用第i个数, dp[i][j]=dp[i-1][j];
class Solution {
public:
int waysToChange(int n) {
//完全背包-动态规划
//用1和不用1
vector<int> coins={0,1,5,10,25};
long long dp[5][n+1];
for(int i=0;i<5;i++)
for(int j=0;j<=n;j++)
dp[i][j]=0;
dp[1][0]=1;
for(int i=1;i<5;i++){
dp[i][0]=1;
for(int j=1;j<=n;j++)
if(j>=coins[i])
dp[i][j]=dp[i][j-coins[i]]+dp[i-1][j];
else
dp[i][j]=dp[i-1][j];
}
return dp[4][n]% 1000000007;
}
};
滚动数组
dp[i][j]只与dp[i-1][j]和dp[i][j-coins[i]]有关,故可以从上往下推,从左往右推,一维数组滚动完成;
减少空间占用;
class Solution {
public:
int waysToChange(int n) {
//完全背包-动态规划
//用1和不用1
vector<int> coins={1,5,10,25};
vector<long long> dp;
dp.resize(n+1,0);
dp[0]=1;
for(int i=0;i<4;i++){
for(int j=coins[i];j<=n;j++)
dp[j]=dp[j-coins[i]]+dp[j];
}
return dp[n]% 1000000007;
}
};
初始化dp[0]=1,表示用凑0有一种办法;