leetcoed刷题6——322. 零钱兑换(动态规划)

题目

这里采纳官方解

方法一,搜索回溯

方法二,动态规划-自上而下

方法三

自己写的用于调试学习的代码

#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
发布了47 篇原创文章 · 获赞 28 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41122796/article/details/104744652
今日推荐