LeetCode(C++)-动态规划-完全背包(零钱兑换 II、组合总和 Ⅳ、零钱兑换、完全平方数、单词拆分)

518. 零钱兑换 II

代码:

class Solution {	//518. 零钱兑换 II
	//动态规划五部曲:
	//1. 确定dp数组以及下标的含义:总金额为j时,组合数的方法为dp[j]
	//2. 确定递推公式:dp[j]+=dp[j-coins[i]]
	//3. dp数组如何初始化:dp[0]=1,其他初始化为0
	//4. 确定遍历顺序:外层for循环遍历硬币,内层for循环从小到大遍历背包容量
	//5. 举例推导dp数组:
public:
	int change(int amount, vector<int>& coins) {
		vector<int> dp(amount + 1, 0);
		dp[0] = 1;
		for (int i = 0; i < coins.size(); ++i) {
			for (int j = coins[i]; j <= amount; ++j) {
				dp[j] += dp[j - coins[i]];
			}
		}
		return dp[amount];
	}
};

377. 组合总和 Ⅳ

代码:

class Solution {	//377. 组合总和 Ⅳ
	//动态规划五部曲:
	//1. 确定dp数组以及下标的含义:目标整数为j时,总和为j的元素组合个数为dp[j]
	//2. 确定递推公式:dp[j]+=dp[j-nums[i]]
	//3. dp数组如何初始化:dp[0]=1,其他为0
	//4. 确定遍历顺序:外层for循环遍历背包容量j,内层for循环遍历物品(nums[i])
	//5. 举例推导dp数组:
public:
	int combinationSum4(vector<int>& nums, int target) {
		vector<int> dp(target + 1, 0);
		dp[0] = 1;
		for (int j = 0; j <= target; ++j) {
			for (int i = 0; i < nums.size(); ++i) {
				if (j - nums[i] >= 0 && dp[j] < INT_MAX - dp[j-nums[i]]) 
					dp[j] += dp[j - nums[i]];
			}
		}
		return dp[target];
	}
};

322. 零钱兑换

代码:

class Solution {	//322. 零钱兑换
	//动态规划五部曲:
	//1. 确定dp数组以及下标的含义:凑成总金额j所需的最少的硬币个数是dp[j]
	//2. 确定递推公式:dp[j]=min(dp[j],dp[j-coins[i]]+1);
	//3. dp数组如何初始化:dp[0]=0,其余为INT_MAX
	//4. 确定遍历顺序:外层for循环遍历物品(coins[i]),内层for循环从小到大遍历背包容量j
	//5. 举例推导dp数组:
public:
	int coinChange(vector<int>& coins, int amount) {
		vector<int> dp(amount + 1, INT_MAX);
		dp[0] = 0;
		sort(coins.begin(), coins.end());
		for (int i = 0; i < coins.size(); ++i) {
			for (int j = coins[i]; j <= amount; ++j) {
				if (dp[j - coins[i]] != INT_MAX)
					dp[j] = min(dp[j], dp[j - coins[i]] + 1);
			}
		}
		if (dp[amount] == INT_MAX) return -1;
		return dp[amount];
	}
};

279. 完全平方数

代码:

class Solution {	//279. 完全平方数
	//动态规划五部曲:
	//1. 确定dp数组以及下标的含义:和为 j 的完全平方数的最少数量为dp[j]
	//2. 确定递推公式:dp[j] = min(dp[j], dp[j - i*i] + 1);
	//3. dp数组如何初始化:dp[0]=0,其余为INT_MAX
	//4. 确定遍历顺序:外层for循环遍历物品(从1到sqrt(n)),内层for循环从小到大遍历背包容量j
	//5. 举例推导dp数组:
public:
	int numSquares(int n) {
		vector<int> dp(n + 1, INT_MAX);
		int numMax = sqrt(n);
		dp[0] = 0;
		for (int i = 1; i <= numMax; ++i) {
			for (int j = i*i; j <= n; ++j) {
				dp[j] = min(dp[j], dp[j - i*i] + 1);
			}
		}
		return dp[n];
	}
};

139. 单词拆分

代码:

class Solution {	//139. 单词拆分
	//动态规划五部曲:
	//1. 确定dp数组以及下标的含义:dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。
	//2. 确定递推公式: if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true
	//3. dp数组如何初始化:d[0]=true,其他为false
	//4. 确定遍历顺序:遍历背包放在外循环,将遍历物品放在内循环
	//5. 举例推导dp数组:
public:
	bool wordBreak(string s, vector<string>& wordDict) {
		unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
		vector<bool> dp(s.size() + 1, false);
		dp[0] = true;
		for (int i = 1; i <= s.size(); ++i) {
			for (int j = 0; j < i; ++j) {
				string word = s.substr(j, i - j);
				if (wordSet.find(word) != wordSet.end() && dp[j]) {
					dp[i] = true;
				}
			}
		}
		return dp[s.size()];
	}
};

参考资料:

代码随想录

你好!对于找零钱问题的动态规划解法,可以使用以下步骤: 1. 定义问题:我们需要找零钱的总金额是amount,可用的硬币面额数组是coins。 2. 初始化状态:创建一个长度为amount+1的数组dp,并将所有元素初始化为无穷大(表示不可达)。 3. 设置初始条件:将dp设为0,表示找零金额为0时,需要0枚硬币。 4. 进行状态转移:遍历金额从1到amount,对于每个金额,遍历硬币面额数组coins,计算最少需要的硬币数量。 a) 如果当前金额减去某个硬币面额大于等于0,并且dp[当前金额-硬币面额]+1的值小于dp[当前金额],则更新dp[当前金额]为dp[当前金额-硬币面额]+1。 5. 返回结果:如果dp[amount]的值为无穷大,则表示无法凑出总金额,否则返回dp[amount]。 下面是一种实现该算法的C代码: ```c #include <stdio.h> #include <limits.h> int coinChange(int* coins, int coinsSize, int amount) { int dp[amount + 1]; dp[0] = 0; for (int i = 1; i <= amount; i++) { dp[i] = INT_MAX; for (int j = 0; j < coinsSize; j++) { if (i - coins[j] >= 0 && dp[i - coins[j]] != INT_MAX) { dp[i] = (dp[i - coins[j]] + 1) < dp[i] ? (dp[i - coins[j]] + 1) : dp[i]; } } } return dp[amount] == INT_MAX ? -1 : dp[amount]; } int main() { int coins[] = {1, 2, 5}; int coinsSize = sizeof(coins) / sizeof(coins[0]); int amount = 11; int result = coinChange(coins, coinsSize, amount); printf("Minimum number of coins required: %d\n", result); return 0; } ``` 这段代码中,我们使用了一个一维数组dp来保存状态,通过遍历硬币面额和金额,不断更新dp数组中的值,最终返回dp[amount]作为结果。注意在代码中INT_MAX表示无穷大,-1表示无法凑出总金额。 希望能帮到你!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海螺蜜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值