动态规划-1049. 最后⼀块⽯头的重量 II

80 阅读1分钟

4月日新计划更文活动 第10天

前言

动态规划专题,从简到难通关动态规划。

每日一题

今天的题目是 1049. 最后一块石头的重量 II,难度为中等

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0

示例 1:

输入: stones = [2,7,4,1,8,1] 输出: 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],这就是最优值。

示例 2:

输入: stones = [31,26,33,21,40] 输出: 5

提示:

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 100

题解

动态规划

对于石头来说,每两个石头之间可以取差值,我们最终的目的,其实也就是要剩下差值最小的石头,比如说 [1,1,1] 这三个分为两个堆,差值为1,再比如[1,2,3,4] 这个也可以分为两个堆 分别是 1+4和2+3,差值为0,也就是最后的结果为0,我们就会发现,我们优先把石头分为两堆,两堆之间的差值,就会使相互抵消最后得到的最优解。

那么这道题也转为了动态规划的问题,dp[i][j] 代表着背包大小为 j 的情况下,i怎么选择才能够更加的接近 j ,最优的情况当然是刚好等于,那就能够完全消掉,这里的 j 代表了实际指的是 sum/2,也就是怎么选择物品,才能够使得值最接近 sum/2

那么接下来用动态规划五部曲来进行解题

dp 数组含义:

定义一个二维数组 dp[i][j],表示前 i 个石头装入容量为 j 的背包中所能装下的最大重量。

递推公式:

对于第 i 个石头(即 stones[i-1]),有两种选择:装或者不装。 若当前石头的重量大于容量 j,不装入该石头:dp[i][j]=dp[i-1][j] 若当前石头的重量小于等于容量 j,装或不装该石头:

dp[i][j]=max(dp[i-1][j], dp[i-1][j-stones[i-1]]+stones[i-1])

其中,dp[i-1][j] 表示不装当前石头的最大重量,dp[i-1][j-stones[i-1]]+stones[i-1] 表示装入当前石头的最大重量。

数组初始化:

dp[0][0] = 0,表示装入一个重量为 0 的物品的最大价值为 0。 为了保证数组完整性,需要将 dp 数组的其他元素初始化为 0。

遍历顺序:

外层循环遍历每个石头(i 从 1 到 n),内层循环遍历容量(j 从 0 到 target),对于每个石头和容量,根据递推公式计算 dp[i][j] 的最大重量。

function lastStoneWeightII(stones: number[]): number {
  const sum = stones.reduce((acc, cur) => acc + cur, 0);
  const target = Math.floor(sum / 2);
  const n = stones.length;
  const dp = new Array(n + 1).fill(0).map(() => new Array(target + 1).fill(0));

  for (let i = 1; i <= n; i++) {
    for (let j = 0; j <= target; j++) {
      if (j < stones[i-1]) {
        dp[i][j] = dp[i-1][j];
      } else {
        dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-stones[i-1]] + stones[i-1]);
      }
    }
  }
  
  const sumA = dp[n][target];
  const sumB = sum - sumA;
  return Math.abs(sumB - sumA);
};

image.png