有一个数组changes,changes中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,对于一个给定值x,请设计一个高效算法,计算组成这个值的方案数。
给定一个int数组changes,代表所有零钱,同时给定它的大小n,另外给定一个正整数x,请返回组成x的方案数,保证n小于等于100且x小于等于10000。
测试样例:
[5,10,25,1],4,15
返回:6
测试样例:
[5,10,25,1],4,0
返回:1
有一个数组changes,changes中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,对于一个给定值x,请设计一个高效算法,计算组成这个值的方案数。
给定一个int数组changes,代表所有零钱,同时给定它的大小n,另外给定一个正整数x,请返回组成x的方案数,保证n小于等于100且x小于等于10000。
[5,10,25,1],4,15
返回:6
[5,10,25,1],4,0
返回:1
import java.util.*;
public class Exchange {
public int countWays(int[] arr, int n,int aim) {
if (arr == null || arr.length == 0 || aim < 0)
return 0;
int[][] dp = new int[arr.length][aim + 1];
for (int i = 0; i < arr.length; i++) {
dp[i][0] = 1;
}
for (int j = 1; arr[0] * j <= aim; j++) {
dp[0][arr[0] * j] = 1;
}
int num = 0;
for (int i = 1; i < arr.length; i++) {
for (int j = 1; j <= aim; j++) {
num = 0;
for (int k = 0; j - arr[i] * k >= 0; k++) {
num += dp[i - 1][j - arr[i] * k];
}
dp[i][j] = num;
}
}
return dp[arr.length - 1][aim];
}
}
import java.util.*;
public class Exchange {
public int countWays(int[] changes, int n, int x) {
// write code here
//dp[i][j]表示使用changes[0~i]的钱币组成金额j的方法数
int[][] dp=new int[n][x+1];
//第一列全为1,因为组成0元就只有一种方法
for(int i=0;i<n;i++)
dp[i][0]=1;
//第一行只有changes[0]的整数倍的金额才能有1种方法
for(int j=0;j*changes[0]<=x;j++){
dp[0][j*changes[0]]=1;
}
//从位置(1,1)开始遍历
for(int i=1;i<n;i++){
for(int j=1;j<=x;j++){
//关键:使用0~i的钱币组成j-changes[i]金额的方法数+使用0~i-1钱币组成j的方法数
dp[i][j]=dp[i-1][j]+(j-changes[i]>=0?dp[i][j-changes[i]]:0);
}
}
return dp[n-1][x];
}
}
import java.util.*;
public class Exchange {
public int countWays(int[] changes, int n, int x) {
// write code here
int[] dp = new int[x + 1];
dp[0] = 1;
for (int change : changes) {
for (int i = 0; i + change <= x; ++i) {
dp[i + change] += dp[i];
}
}
return dp[x];
}
}
import java.util.*;
public class Exchange {
public int countWays(int[] changes, int n, int x) {
// 方法一:递归
// return recursion(changes,0,n-1,x);
// 方法二:迭代
int[] arr = new int[x + 1];
arr[0] = 1;
int i = 0, j = 0;
for (i = 0; i < n; ++i) {
for (j = 0; j+changes[i] <= x; j++) {
arr[j+changes[i]]+=arr[j];
}
}
return arr[x];
}
public int recursion(int[] changes, int begin, int end, int target) {
// 边界条件
if (target == 0)
return 1;
if (begin > end || target < 0)
return 0;
int count = 0;
int times = 0;
// 找零的过程中使用了times次changes[begin]
// 在后续的找零中,不再使用changes[begin]
while (times * changes[begin] <= target) {
count += recursion(changes, begin + 1, end, target - times * changes[begin]);
++times;
}
return count;
}
}
class Exchange {
public:
int countWays(vector<int> changes, int n, int x) {
int dp[x+1];
for(int i =0;i<=x;i++)
dp[i] = 0;
dp[0] = 1;
for(int i =0;i<n;i++)
for(int j = 0;j+changes[i]<=x;j++)
dp[j+changes[i]] += dp[j];
return dp[x];
}
};
class Exchange {
public:
int countWays(vector<int> changes, int n, int x) {
// write code here
int dp[ x+1 ] ;
int i,j ;
for( i=1; i<=x; i++ )
dp[i] = 0 ;
dp[ 0 ] = 1 ;//0元钱找零全部不选,所以方案数为1
for( i=0; i<n; i++ )//dp[j]=dp[j](不选changes[i])+dp[ j-changes[i] ](选择一个changes[i])
for( j=changes[i]; j<=x; j++ )
dp[ j ] = dp[j] + dp[ j-changes[i] ] ;
return dp[ x ] ;
}
};
class Exchange { class Exchange {
public:
int countWays(vector<int> changes, int n, int x) {
// write code here
vector<int> brr(x+1,0);
brr[0]=1;
for(int i=0;i<n;++i)
{
for(int j=changes[i];j<x+1;++j)
{
brr[j]+=brr[j-changes[i]];
}
}
return brr[x];
}
}; // 暴力递归
public int countWays1(int[] changes, int n, int x) {
if (x == 0) {
return 1;
} else if (n == 0) {
return 0;
}
int res = countWays1(changes, n - 1, x);
if (x >= changes[n - 1]) {
for (int k = 1; k <= x / changes[n - 1]; k++) {
res += countWays1(changes, n - 1, x - k * changes[n - 1]);
}
}
return res;
}
// 动态规划
public int countWays2(int[] changes, int n, int x) {
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++) {
dp[i][j] = dp[i - 1][j];
if (j >= changes[i - 1]) {
for (int k = 1; k <= j / changes[i - 1]; k++) {
dp[i][j] += dp[i - 1][j - k * changes[i - 1]];
}
}
}
}
return dp[n][x];
}
// 动态规划的空间优化
public int countWays3(int[] changes, int n, int x) {
int[] dp = new int[x + 1];
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = x; j >= 1; j--) {
if (j >= changes[i - 1]) {
for (int k = 1; k <= j / changes[i - 1]; k++) {
dp[j] += dp[j - k * changes[i - 1]];
}
}
}
}
return dp[x];
}
public static int countWays(int[] changes, int n, int x) { // write code here int[] memo = new int[x + 1]; memo[0] = 1; for (int i = 0; i < n; i++) { for (int j = changes[i]; j <= x; j++) { memo[j] += memo[j - changes[i]]; } } return memo[x]; }
class Exchange {
public:
int countWays(vector<int> changes, int n, int x) {
// write code here
vector<long> dp(x+1,0);
dp[0]=1;
for(int i=0;i<n;i++)
for(int j=1;j<=x;j++)
if(j>=changes[i])
dp[j]+=dp[j-changes[i]];
return dp[x];
}
};
class Exchange {
public:
int countWays(vector<int> changes, int n, int x) {
int dp[n][x+1];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
dp[i][0] = 1;
for(int j=0;j*changes[0]<=x;j++)
dp[0][j*changes[0]] = 1;
for(int i=1;i<n;i++)
for(int j=1;j<=x;j++)
{
if(j - changes[i] >= 0)
dp[i][j] = dp[i-1][j] + dp[i][j-changes[i]];
else
dp[i][j] = dp[i-1][j]; } return dp[n-1][x];
}
};
//使用动态规划
import java.util.*;
public class Exchange {
private int[][] map;
private int[] changes;
private int dp(int x, int y) { //使用前x种货币组成y元的方法数
if (x < 0 || y < 0) return 0;
if (map[x][y] != 0) return map[x][y]; //将数据保存在数组中,避免重复递归
if (y == 0) {
map[x][y] = 1;
return 1; //组成0元的方法数为1
} else {
if (x == 0) {
map[x][y] = 0;
return 0; //0种货币组成非0元的方法数为0
}
}
if (x == 1) {
if (y % changes[0] == 0) {
map[x][y] = 1;
return 1; //只使用第一种货币,只有当y为此货币整数倍时方法数为1
}
}
int k = y / changes[x - 1]; //能使用第x种货币的数量上限
int res = 0;
for (int i = 0; i <= k; i++) {
//是否能使用i个编号为x的货币取决于能否使用x-1种货币组成y - i * changes[x - 1]元
res += dp(x - 1, y - i * changes[x - 1]);
}
map[x][y] = res;
return res;
}
public int countWays(int[] changes, int n, int x) {
this.map = new int[n + 1][x + 1];
this.changes = changes;
return dp(n, x);
}
}
/**
* @param changes 零钱面值种类的数组
* @param n changes数组的大小
* @param x 要兑换的钱数
* @return 返回可以兑换的不同方式的数量
*/
public int countWays(int[] changes, int n, int x) {
// 待兑换的金额是i,可用的范围是0-j-1
// i = x,j = 0-n-1
int[][] dp = new int[x + 1][n];
// 当待兑换的金额是0的时候,都是只有一种
for (int i = 0; i < n; i++)
dp[0][i] = 1;
// 第1列,待兑换的钱是i,因为只能用第一种零钱,所以只有当是第一种零钱的整数倍的时候,才有一种兑换方法
for (int i = 1; i <= x; i++) {
if (i % changes[0] == 0) {
dp[i][0] = 1;
}
}
//对于dp[i][j],i是待兑换的钱数,j是changes[0-j]的钱币种类
//dp[i][j] += dp[i][j-1],不用changes[j]这种钱
//dp[i][j] += dp[i-changes[j]][j],用了一张changes[j]这种钱,剩下的待兑换的钱是i-changes[j]
//只有以上两种可能
for (int i = 1; i <= x; i++) {
for (int j = 1; j < n; j++) {
if (i - changes[j] >= 0)
dp[i][j] += (dp[i][j-1] + dp[i - changes[j]][j]);
else
dp[i][j] += dp[i][j-1];
}
}
return dp[x][n - 1];
}
classExchange {public:intcountWays(vector<int> changes, intn, intx) {// write code hereif(changes.size()==0|| changes.empty() || x<0)return0;vector<int> dp(x+1);for(intj=0;changes[0]*j<=x;j++)dp[changes[0]*j]=1;for(inti=1;i<changes.size();i++)for(intj=1;j<=x;j++)dp[j]+=j-changes[i]>=0? dp[j-changes[i]]:0;returndp[x];}};
# -*- coding:utf-8 -*-
class Exchange:
def countWays(self,changes,n,x):
# write code here
dp=[]
for i in range(n):
dp.append([0]*(x+1))
for i in range(n):
dp[i][0]=1
j=0
while j*changes[0]<=x:
dp[0][j*changes[0]]=1
j+=1
for i in range(1,n):
for j in range(1,x+1):
if j-changes[i]>=0:
dp[i][j]=dp[i-1][j]+dp[i][j-changes[i]]
else:
dp[i][j]=dp[i-1][j]
return dp[-1][-1]
class Exchange {
public:
int countWays(vector<int> changes, int n, int x) {
if (changes.empty() || n <= 0 || x < 0) {
return 0;
}
int rows = changes.size();
int cols = x;
vector<vector<int>> dp(rows + 1, vector<int>(cols + 1, 0));
for (int i = 0; i <= rows; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
if (j - changes[i - 1] >= 0) {
dp[i][j] += dp[i][j - changes[i - 1]];
}
dp[i][j] += dp[i - 1][j];
}
}
return dp[rows][cols];
}
};
public int countWays(int[] changes, int n, int x) {
//初始化
int[] dp = new int[x + 1];
for (int i = 0; i < x + 1; i++)
dp[i] = i % changes[changes.length - 1] == 0 ? 1 : 0;
//动态更新
for (int i = changes.length - 2; i >= 0; i--) {
for (int j = 0; j < x + 1; j++) {
dp[j] += j >= changes[i] ? dp[j - changes[i]] : 0;
}
}
return dp[x];
}