题目:
定义一种新货币,有n(n<=50)种不同的币值,其中币值为 value(value<=50) 的有 w(w<=20) 个。现在你有 x(x<=100) 元,但是你想将 x 元换成若干零钱,请问有多少种换钱的方案?
方法一:动态规划
这是背包问题的变形,我们可以定义dp[i][j]为用前i种硬币凑出金额j的方案数,
初始条件为,因为前i种硬币凑出金额0的方案数为1
第i种硬币数量有a[i-1][1]个,因此枚举第i种硬币的数量,则前i种硬币凑出金额j的方案数等于前种硬币凑出金额j不加入k个第i种硬币的方案数的累加和,因此状态转移方程为
import java.util.*;
public class Solution {
/**
*
* @param n int整型 :牛币值种类数
* @param x int整型 :牛妹拥有的钱数
* @param a int整型二维数组 :第二个vector中的第一列表示币值,第二列表示牛牛拥有币值的个数
* @return int整型
*/
public int solve (int n, int x, int[][] a) {
// write code
//用前i种币值凑出金额j的方案数为dp[i][j]
int[][]dp=new int[n+1][x+1];
for(int i=0;i<=n;i++)dp[i][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=x;j++){
for(int k=0;k<=a[i-1][1];k++){//枚举第i种硬币的个数
if(j>=k*a[i-1][0])//如果金额数量大于等于k个第i种硬币则可以将k个第i种硬币放入
dp[i][j]+=dp[i-1][j-k*a[i-1][0]];
else break;
}
}
}
return dp[n][x];
}
}复杂度:
时间复杂度: ,三层循环,最内层循环k循环次数不超过
空间复杂度:,dp数组的大小不超过
方法二:记忆化搜索
将动态规划改写为记忆化搜索,用记忆数组记录已经计算过的方案数,避免大量的重复运算
递归公式为:
import java.util.*;
public class Solution {
/**
*
* @param n int整型 :牛币值种类数
* @param x int整型 :牛妹拥有的钱数
* @param a int整型二维数组 :第二个vector中的第一列表示币值,第二列表示牛牛拥有币值的个数
* @return int整型
*/
int[][]memory;
public int solve (int n, int x, int[][] a) {
// write code
//用i种币值凑出金额j的方案数为dp[i][j]
memory=new int[n+1][x+1];
for(int i=0;i<a.length;i++)memory[i][0]=1;//初始化记忆数组,i种硬币凑出金额0的方案数都为1
return dp(n,x,a);
}
int dp(int i,int j,int[][]a){
//递归终止条件
if(i>=0&&j==0)return 1;
if(i==0&&j>0)return 0;
//已经计算过值直接返回
if(memory[i][j]!=0)return memory[i][j];
//前i种硬币凑成金额j的方案数由前i-1种硬币凑出金额j-k个第i种硬币的方案数递推而来
for(int k=0;k<=a[i-1][1];k++){
if(j>=k*a[i-1][0])
memory[i][j]+=dp(i-1,j-k*a[i-1][0],a);
}
return memory[i][j];
}
}复杂度:
时间复杂度:递归次数不超过,每次递归时间复杂度为
,因此时间复杂度为
空间复杂度:,记忆数组和递归运行时栈大小不超过

京公网安备 11010502036488号