题目
解
这里采纳官方解
方法一,搜索回溯
方法二,动态规划-自上而下
方法三
自己写的用于调试学习的代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int global = 0;
int max_deep = 0;
#if 0
class Solution
{
int coinChange(int idxCoin,vector<int> &coins, int amount,int deep)
{
deep++;
if (deep > max_deep) max_deep = deep;
global++;
//cout << "\n\n————————————这是在第" << deep << "层————————————\n\n";
//cout << "这是f(" << idxCoin << ")的调用" << endl;
if (amount == 0)//递归出口,求和本身为0时,需要0个硬币==产生一个可行解
{
//cout << "\n\n————————————这是在第" << deep << "层————————————\n\n";
//cout << "这是f(" << idxCoin << ")的返回,返回值为0" << endl;
return 0;
}
if (idxCoin < coins.size() && amount>0)//每个合法的硬币面值
{
int maxVal = amount / coins[idxCoin];//第idxCoin个硬币面值的个数最大值
int minCost = INT_MAX;//最优解硬币个数
for (int x = 0; x <= maxVal; x++)//可能的第idxCoin个硬币面值的个数
{
if (amount >= x * coins[idxCoin])//硬币和没有达到目标时
{
//cout << "\n\n————————————这是在第" << deep << "层中的循环————————————\n\n";
//cout << "\t当前硬币面值为:" << coins[idxCoin]<< " 当前硬币数x:" << x<< endl;
int res = coinChange(idxCoin + 1, coins, amount - x * coins[idxCoin],deep);
//下一个硬币面额在剩余钱数的可能解
if (res != -1)
{
/*
cout << "\n\n————————————这是在第" << deep << "层————————————\n\n";
cout << "\n\n------这是一个可行解------" << endl;
cout << "\t当前硬币面值为:" << coins[idxCoin]
<< " 未更新前,最优解为:" << minCost
<< "\n\t当前硬币数x:" << x
<< " 下一轮最优解硬币数量为:" << res
<< "\n\t得到的可行解为:" << res+x
<< "\n\t所以最佳答案为:"<< min(minCost, res + x)
<< endl;
*/
minCost = min(minCost, res + x);//解存在的话,更新最小硬币个数
}
}
}
if (minCost != INT_MAX)
{
/*
cout << "\n\n————————————这是在第" << deep << "层————————————\n\n";
cout << "\n\n------This is a band of solution------" << endl;
cout << "\t当前硬币面值为:" << coins[idxCoin] << " 最优解硬币数量为:" << minCost << endl;
*/
}
//cout << "\n\n————————————这是在第" << deep << "层————————————\n\n";
//cout << "这是f(" << idxCoin << ")的返回,返回值为" << (minCost == INT_MAX ? -1 : minCost)<< endl;
return minCost == INT_MAX ? -1 : minCost;//没有可行解即minCost == INT_MAX,返回-1;有可行最优解,返回硬币数
}
//cout << "\n\n————————————这是在第" << deep << "层————————————\n\n";
//cout << "这是f(" << idxCoin << ")的返回,返回值为-1" << endl;
return -1;//没有硬币组合返回-1;
}
public:
int coinChange(vector<int> &coins, int amount)
{
return coinChange(0, coins, amount,0);
}
};
int main()
{
vector<int> coins{1,2,5};
Solution s;
int amount = 1000;
cout << "结果是:" << s.coinChange(coins, amount) << endl;
cout << "总共调用了" << global << "次递归函数" << endl;
cout << "递归最大深度为" << max_deep << endl;
//amount=10对应调用90次递归 amount=100对应2万 amount=1000对应1700万
}
#endif
#if 0
class Solution
{
vector<int>count;//先验数组,避免重复计算,count[rem-1]=剩余金额rem最小的硬币总和数
int dp(vector<int> &coins, int rem,int deep)//rem是剩余总金额,dp(coins, rem)返回count[rem-1]=剩余金额rem最小的硬币总和数
{
deep++;
if (deep > max_deep) max_deep = deep;
global++;
if (rem < 0) return -1;//金额小于0,说明上一轮剩余金额减去探索的硬币面值小于0,不合法
if (rem == 0) return 0;
if (count[rem - 1] != 0) return count[rem - 1];
int Min = INT_MAX;//存本次调用count[rem - 1]=Min,即本轮剩余金额rem最小的硬币总和数
for (int coin : coins)//C++11新特性循环
{
int res = dp(coins, rem - coin,deep);//式1,dp(coins, rem - coin)返回count[rem-coin-1]=剩余金额rem-coin最小的硬币总和数
if (res >= 0 && res < Min)
Min = res + 1;//式2
}
count[rem - 1] = Min == INT_MAX ? -1 : Min;//式3,式3、式2、式1合起来构成了状态转移方程
return count[rem - 1];
}
public:
int coinChange(vector<int> &coins, int amount)
{
if (amount < 1) return 0;
count.resize(amount);//相当于初始化,默认为0
return dp(coins, amount,0);
}
};
int main()
{
vector<int> coins{ 1,2,5 };
Solution s;
int amount = 1000;
cout << "结果是:" << s.coinChange(coins, amount) << endl;
cout << "总共调用了" << global << "次递归函数" << endl;
cout << "递归最大深度为" << max_deep << endl;
return 0;
//amount=10对应调用31次递归 amount=100对应301 amount=1000对应3001
}
#endif
#if 1
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int Max = amount + 1;
vector<int> dp(amount + 1, Max);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int j = 0; j < (int)coins.size(); ++j) {
global++;
if (coins[j] <= i) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1);
max_deep++;
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
};
int main()
{
vector<int> coins{ 1,2,5 };
Solution s;
int amount = 10;
cout << "结果是:" << s.coinChange(coins, amount) << endl;
cout << "总共循环了" << global << "次" << endl;
cout << "计算次数为" << max_deep << endl;
return 0;
//amount=10对应调用30次递归 amount=100对应300 amount=1000对应3000
}
#endif