开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情
1049. 最后一块石头的重量 II 题目描述:有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
- 如果
x == y,那么两块石头都会被完全粉碎; - 如果
x != y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。
| 示例1 | 示例2 |
|---|---|
输入:stones = [2,7,4,1,8,1] 输出: 解释: 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1], 组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1], 组合 2 和 1,得到 1,所以数组转化为 [1,1,1], 组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。 | 输入:stones = [31,26,33,21,40] 输出: |
中规中矩的动态规划
简化此问题:我们在每个元算前添加上 + / - 号之后,将所有元素相加后的值最小是多少?本题就与 # 494. 目标和 有着异曲同工之处。我们假设可将所有的石头分成两个部分,如果我们想让两部分作用后的结果最小,那么这两个部分各自所有元素之和就要逼近 ,其中 是数组 所有元素之和。因此这道题就转化成了一道传统的 0-1 背包问题,背包容量为 ,物品为 ,试问不超过背包容量的最大承重是多少。
1、确定 dp 状态数组
定义 为在 区间内选择元素装进容量为 的背包后的最大重量,其中 ,, 是所有 元素重量之和。
2、确定 dp 状态方程
当 时,有 ;
当 时,有
综上所述,
3、确定 dp 初始状态
-
代表在 区间内选择元素装进容量为 的背包后的最大重量,此时没有元素可以选择,故 ;
-
代表在 区间内选择元素装进容量为 的背包后的最大重量,此时背包容量0,故 ;
4、确定遍历顺序
对于0-1背包的二维情况,可以先遍历物品再遍历背包
-
外层循环遍历物品,从 遍历到 ;
-
内层循环遍历背包,从 遍历到 。
5、确定最终返回值
仅代表的是 区间内选择元素装进容量为 的背包后的最大重量,最终的返回值应为 。
6、代码示例
/**
* 空间复杂度 O(n*sum),n是stones数组的长度,sum是stones元素之和
* 时间复杂度 O(n*sum)
*/
function lastStoneWeightII(stones: number[]): number {
const n = stones.length;
const sum = stones.reduce((acc, curr) => acc + curr, 0);
const weight = ~~(sum / 2);
const dp = Array.from({ length: n + 1 }, () => new Array(weight + 1).fill(0));
for (let i = 1; i <= n; i++) {
const stone = stones[i - 1];
for (let j = 1; j <= weight; j++) {
if (j < stone) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stone] + stone);
}
}
}
return sum - 2 * dp[n][weight];
};
0-1 背包问题可以压缩空间:
-
定义 是装入容量为 的背包的最大重量。
-
转移方程为 。
-
初始化状态 。
-
先遍历物品,再 倒序 遍历背包。
-
最终返回值
/**
* 空间复杂度 O(n*sum),n是stones数组的长度,sum是stones元素之和
* 时间复杂度 O(sum)
*/
function lastStoneWeightII(stones: number[]): number {
const sum = stones.reduce((acc, curr) => acc + curr, 0);
const weight = ~~(sum / 2);
const dp = new Array(weight + 1).fill(0);
for (const stone of stones) {
for (let j = weight; j >= stone; j--) {
dp[j] = Math.max(dp[j], dp[j - stone] + stone);
}
}
return sum - 2 * dp[weight];
};