diff --git a/include/s1049_last_stone_weight_ii.hpp b/include/s1049_last_stone_weight_ii.hpp new file mode 100644 index 0000000..0642a2a --- /dev/null +++ b/include/s1049_last_stone_weight_ii.hpp @@ -0,0 +1,14 @@ +#ifndef S1049_LAST_STONE_WEIGHT_II_HPP +#define S1049_LAST_STONE_WEIGHT_II_HPP + +#include +#include + +using namespace std; + +class S1049 { + public: + int lastStoneWeightII(vector& stones); +}; + +#endif diff --git a/notes/src/dynamic-programming.md b/notes/src/dynamic-programming.md index fe2d1f4..9e1a11d 100644 --- a/notes/src/dynamic-programming.md +++ b/notes/src/dynamic-programming.md @@ -7,7 +7,7 @@ 1. 确定 `dp[i]` 是什么 2. 确定递推公式 3. `dp` 数组如何初始化 -4. 确定遍历顺序(从前向后还是从后向前) +4. 确定遍历顺序(从前向后还是从后向前)和范围 5. 推几个来验证 技巧: diff --git a/notes/src/knapsack.md b/notes/src/knapsack.md index 31f27c8..725c2f6 100644 --- a/notes/src/knapsack.md +++ b/notes/src/knapsack.md @@ -124,3 +124,38 @@ void bag_problem_1d() { - 遍历顺序: - `i` 从前往后,范围是 `1 <= i < length` - `j` 从后往前,范围是 `nums[i] <= j <= target` + +本题中可以不初始化第一层,然后 `i` 从 0 开始。 + +## [1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii/) + +仔细思考一下每个石头重量的加减方式,你会发现其实最终的重量可以这样表示: + +`final = k0 * w0 + k1 * w1 + k2 * w2 + ...` + +其中 `ki` 为 `+1` 或 `-1`,`wi` 为第 `i` 个石头的重量。 + +那么 `ki` 取负的所有石头重量之和我们表示为 `neg`,其它石头重量之和为 `total - neg`。 + +我们的目的就是要在 `neg <= total/2` 的前提下,让 `neg` 达到最大。 + +这就是一个 01 背包问题。 + +- `i` 对应石头下标,每个石头的重量为 `stones[i]`,价值为 `stones[i]` +- `j` 对应背包容量,最大为 `total/2` + +我们直接上滚动数组: + +- `dp[j]` 表示从 0 ~ i 中选石头,放进容量为 `j` 的背包,所能达到的最大价值 +- 迭代公式: + - `if (j < stones[i]) dp[j] = dp[j]` + - `if (j >= stones[i]) dp[j] = max{dp[j], dp[j - stones[i]] + stones[i]}` + - 第二层迭代的范围是 `stones[i] ~ total/2` +- 初始化: + - `if (j < stones[0]) dp[j] = 0` + - `if (j >= stones[0]) dp[j] = stones[0]` +- 遍历: + - `i` 从 1 到 length - 1 + - `j` 从 `total/2` 向下取整,遍历到 `stones[i]` + +本题中可以不初始化第一层,然后 `i` 从 0 开始。 diff --git a/src/s1049_last_stone_weight_ii.cpp b/src/s1049_last_stone_weight_ii.cpp new file mode 100644 index 0000000..316f792 --- /dev/null +++ b/src/s1049_last_stone_weight_ii.cpp @@ -0,0 +1,15 @@ +#include "s1049_last_stone_weight_ii.hpp" + +int S1049::lastStoneWeightII(vector& stones) { + int total{0}; + int len = stones.size(); + vector dp(30 * 1000 / 2 + 1, 0); + for (int i{0}; i < len; ++i) total += stones[i]; + int limit = total >> 1; + for (int i{0}; i < len; ++i) { + for (int j = limit; j >= stones[i]; --j) { + dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]); + } + } + return total - dp[limit] * 2; +} diff --git a/tests/s1049_last_stone_weight_ii.cpp b/tests/s1049_last_stone_weight_ii.cpp new file mode 100644 index 0000000..eecd481 --- /dev/null +++ b/tests/s1049_last_stone_weight_ii.cpp @@ -0,0 +1,24 @@ +#include "s1049_last_stone_weight_ii.hpp" + +#include + +TEST(Problem1049, Case1) { + vector stones{2, 7, 4, 1, 8, 1}; + int expected{1}; + S1049 solution; + EXPECT_EQ(solution.lastStoneWeightII(stones), expected); +} + +TEST(Problem1049, Case2) { + vector stones{31, 26, 33, 21, 40}; + int expected{5}; + S1049 solution; + EXPECT_EQ(solution.lastStoneWeightII(stones), expected); +} + +TEST(Problem1049, Case3) { + vector stones{57, 32, 40, 27, 35, 61}; + int expected{4}; + S1049 solution; + EXPECT_EQ(solution.lastStoneWeightII(stones), expected); +}