给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
输入: amount = 5, coins = [1, 2, 5]
输出: 4
解释: 有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
输入: amount = 3, coins = [2]
输出: 0
解释: 只用面额2的硬币不能凑成总金额3。
输入: amount = 10, coins = [10]
输出: 1
解题
代码:
class Solution {
public:
int change(int amount, vector<int>& coins) {
int row=coins.size()+1;
int col=amount+1;
if(amount==0)
return 1;
if(row==1)
return 0;
vector<vector<int>> dp(row,vector<int>(col,0));
for(int i=0;i<row;i++)
dp[i][0]=1;
for(auto a:dp[0])
cout<<a;
cout<<endl;
for(int i=1;i<row;i++)
{
for(int j=1;j<col;j++)
{
if(j-coins[i-1]<0)
dp[i][j]=dp[i-1][j];
else
dp[i][j]=dp[i-1][j]+dp[i][j-coins[i-1]];
}
}
for(auto b:dp[1])
cout<<b;
return dp[row-1][col-1];
}
};
那么接下来如何进行状态压缩呢
我们发现只是和dp[i][…]以及dp[i-1][…]有关.所以压缩;
举个例子,我们将table[0][j]
状态存在二维表的第0行,接着推出table[1][j]
对应的值,并将table[1][j]
的状态存放于二维表的第1行。再接着推出table[2][j]
的状态时,table[0][j]
的状态已经没有保存意义了,因此直接将table[2][j]
的状态保存到二维表的第0行,并以此类推,使数组空间得到循环利用。
有时候压缩也要注意遍历的方向,不可以影响后面的结果
比如
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
class Solution {
public:
int change(int amount, vector<int>& coins) {
int row=coins.size()+1;
int col=amount+1;
if(amount==0)
return 1;
if(row==1)
return 0;
vector<int> dp(amount+1,0);
dp[0]=1;
for(int i=1;i<row;i++)
{
for(int j=1;j<col;j++)
{
if(j-coins[i-1]>=0)
dp[j]=dp[j]+dp[j-coins[i-1]] ;
}
}
return dp[amount];
}
};
class Solution {
public:
bool canPartition(vector<int>& nums) {
//动态规划
int sum=0;
for(auto a:nums)
sum+=a;
if(sum%2!=0) return false;
sum=sum/2;
// int row=nums.size()+1;
// int col=sum+1;
// vector<vector<bool>> dp(row,vector<bool>(col,false));
// for(int i=0;i<row;i++)
// dp[i][0]=true;
// cout<<dp[1][0];
// for(int i=1;i<row;i++)
// {
// for(int j=1;j<col;j++)
// {
// if(j-nums[i-1]<0)
// dp[i][j]=dp[i-1][j];
// else
// dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i-1]];
// }
// }
// return dp[row-1][col-1];
vector<bool> dp(sum+1,false);
dp[0]=true;
for(int i=1;i<=nums.size();i++)
{
for(int j=dp.size();j>0;j--)// **为了不影响结果,所以选择遍历方向时候要适当改变**
{
if(j-nums[i-1]>=0)
dp[j]=dp[j-nums[i-1]]||dp[j];
}
}
return dp[sum];
}
};