创作目的:为了方便自己后续复习重点,以及养成写博客的习惯。
一、零钱兑换II
思路:参考carl文档
1、确定dp数组以及下标的含义:凑成总金额j的货币组合数为dp[j]。
2、确定递推公式:dp[j] 就是所有的dp[j - coins[i]]相加,递推公式为dp[j] += dp[j - coins[i]]。
3、dp数组如何初始化:dp[0] = 1理解为凑成总金额0的货币组合数为1,其余下标dp[j]初始化为0,这样累计加dp[j - coins[i]]时不会影响dp[j]。
4、确定遍历顺序:
外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)(组合)
for (int i = 0; i < coins.size(); i++) {
for (int j = coins[i]; j <= amount; j++) { // 遍历背包
dp[j] += dp[j - coins[i]];
}
}
5、举例推导dp数组
ledcode题目:https://leetcode.cn/problems/coin-change-ii/description/
AC代码:
int change(int amount, int* coins, int coinsSize) {
int dp[amount + 1];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 0; i < coinsSize; i++) {
for (int j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
二、组合总数和 IV
思路:参考carl文档
1、确定dp数组以及下标的含义:凑成目标正整数为i的排列个数为dp[i]。
2、确定递推公式:dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导出来。
排列个数dp[i - nums[j]],是dp[i]的一部分。求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]]。
3、dp数组如何初始化:由递推公式dp[i] += dp[i - nums[j]]知dp[0]初始化为1,非0下标的dp[i]初始化为0,这样才不会影响dp[i]累加dp[i - nums[j]]。
4、确定遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。(排列)
5、举例来推导dp数组
lecode题目:https://leetcode.cn/problems/combination-sum-iv/description/
AC代码:
int combinationSum4(int* nums, int numsSize, int target) {
int dp[target + 1];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 1; i <= target; i++) {
for (int j = 0; j < numsSize; j++) {
if (nums[j] <= i && dp[i - nums[j]] < INT_MAX - dp[i]) {
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
}