s0518
All checks were successful
ci/woodpecker/push/test Pipeline was successful

This commit is contained in:
Sainnhe Park 2023-02-09 17:06:22 +08:00
parent 9a31621c9a
commit 8dc3a66883
4 changed files with 72 additions and 4 deletions

View File

@ -0,0 +1,13 @@
#ifndef S0518_COIN_CHANGE_II_HPP
#define S0518_COIN_CHANGE_II_HPP
#include <vector>
using namespace std;
class S0518 {
public:
int change(int amount, vector<int>& coins);
};
#endif

View File

@ -100,6 +100,15 @@ void knapsack_problem_1d() {
**A:** 如果从后往前的话,`dp[j - weight[i]] + value[i]` 就用的是上一层的数据(这才是我们想要的),但如果从前往后的话,`dp[j - weight[i]] + value[i]` 就用的是这一层的数据,这将会导致物品被重复放进去。 **A:** 如果从后往前的话,`dp[j - weight[i]] + value[i]` 就用的是上一层的数据(这才是我们想要的),但如果从前往后的话,`dp[j - weight[i]] + value[i]` 就用的是这一层的数据,这将会导致物品被重复放进去。
**Q: 怎样初始化?**
**A:**
1. 先确定 `dp[j]` 应该初始化为多少,一般是 `0`
2. 接下来确定 `dp[0]` 应该初始化为多少,我们直接看下一次访问到 `dp[0]` 时是什么情况就行,当访问到 `dp[0]` 时它应该是多少
3. 我们接下来看看用当前的初始化值跑 `i = 0` 也就是第一层,逻辑是否正确。如果逻辑正确,那么第一层 for 循环的 `i` 就从 `0` 开始
4. 如果不正确,我们专门对 `i = 0` 也就是第一层进行初始化,然后第一层 for 循环的 `i``1` 开始。
### [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) ### [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/)
二维数组: 二维数组:
@ -129,8 +138,6 @@ void knapsack_problem_1d() {
本题中可以不初始化第一层,然后 `i` 从 0 开始。 本题中可以不初始化第一层,然后 `i` 从 0 开始。
考虑需不需要初始化第一层其实很简单,就看如果不初始化的话,第一层循环的逻辑是否正确。
### [1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii/) ### [1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii/)
仔细思考一下每个石头重量的加减方式,你会发现其实最终的重量可以这样表示: 仔细思考一下每个石头重量的加减方式,你会发现其实最终的重量可以这样表示:
@ -164,8 +171,6 @@ void knapsack_problem_1d() {
本题中可以不初始化第一层,然后 `i` 从 0 开始。 本题中可以不初始化第一层,然后 `i` 从 0 开始。
考虑需不需要初始化第一层其实很简单,就看如果不初始化的话,第一层循环的逻辑是否正确。
## 完全背包 ## 完全背包
和 01 背包的区别就在于01 背包的每个元素只能用一次,而完全背包的每个物品能够重复使用。 和 01 背包的区别就在于01 背包的每个元素只能用一次,而完全背包的每个物品能够重复使用。
@ -186,3 +191,13 @@ void complete_knapsack_problem_1d() {
} }
} }
``` ```
### [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/)
- `dp[j]` 的含义是从 0 ~ i 这些硬币中选择,组合成总金额为 j 的组合数
- `dp[j] += dp[j - coins[i]]`
- 初始化:
- 当 `i = 0` 的时候,也就是只有 `coins[0]` 这一种硬币的时候,当 `j` 可以被 `coins[0]` 整除的时候就赋值为 `1`,否则赋值为 `0`
- 一种特殊情况是 `dp[0]`,它表示组合成总金额为 `0` 的组合数,我们必须把它赋值为 `1`,这是因为当我们执行 `dp[j] += dp[j - coins[i]]` 的时候,如果 `j == coins[i]` 那么显然应该自增 `1`
- 看看能不能不初始化第一层,我们直接删掉代码试试发现可以,那就不初始化第一层。
- 遍历顺序都是从前向后

View File

@ -0,0 +1,13 @@
#include "s0518_coin_change_ii.hpp"
int S0518::change(int amount, vector<int>& coins) {
int len = coins.size();
vector<int> dp(amount + 1, 0);
dp[0] = 1;
for (int i{0}; i < len; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}

View File

@ -0,0 +1,27 @@
#include "s0518_coin_change_ii.hpp"
#include <gtest/gtest.h>
TEST(Problem518, Case1) {
vector<int> coins{1, 2, 5};
int amount{5};
int expected{4};
S0518 solution;
EXPECT_EQ(solution.change(amount, coins), expected);
}
TEST(Problem518, Case2) {
vector<int> coins{2};
int amount{3};
int expected{0};
S0518 solution;
EXPECT_EQ(solution.change(amount, coins), expected);
}
TEST(Problem518, Case3) {
vector<int> coins{10};
int amount{10};
int expected{1};
S0518 solution;
EXPECT_EQ(solution.change(amount, coins), expected);
}