leetcode-1049-最后一块石头的重量II

[题目描述]

  1. 有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
  2. 每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x y,且 x <= y。那么粉碎的可能结果如下:
  3. 如果 x == y,那么两块石头都会被完全粉碎;
  4. 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x
  5. 最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0
  6. 示例 1
  7. 输入:stones = [2,7,4,1,8,1]
  8. 输出:1
  9. 解释:
  10. 组合 2 4,得到 2,所以数组转化为 [2,7,1,8,1],
  11. 组合 7 8,得到 1,所以数组转化为 [2,1,1,1],
  12. 组合 2 1,得到 1,所以数组转化为 [1,1,1],
  13. 组合 1 1,得到 0,所以数组转化为 [1],这就是最优值。
  14. 示例 2
  15. 输入:stones = [31,26,33,21,40]
  16. 输出:5
  17. 示例 3
  18. 输入:stones = [1,2]
  19. 输出:1
  20. 提示:
  21. 1 <= stones.length <= 30
  22. 1 <= stones[i] <= 100
  23. Related Topics 动态规划
  24. 👍 214 👎 0

[题目链接]

leetcode题目链接

[github地址]

代码链接

[思路介绍]

思路一:动态规划

  • 题目分析,从正整数数组中找到和差target的最小值
  • 根据leetcode-494-目标和 可以思考得出
  • 和差值即为绝对值的最小差值最大平分数组和
  • 也就是说又转换成了背包问题
  • 假设寻找到的决策结果为res,元素绝对值总和为sum,最后求得的最小价值差,也就是结果 = sum - res - res
  • 定义一个dp方程 dp[i][j]表示前i个元素,凑成绝对值j的最大价值(边界范围sum/2)
  1. public int lastStoneWeightII(int[] stones) {
  2. int sum = 0, n = stones.length;
  3. //corner case
  4. if (n == 1) {
  5. return stones[0];
  6. }
  7. //求数组所有元素和
  8. for (int i : stones
  9. ) {
  10. sum += i;
  11. }
  12. int edge = sum / 2 + 1;
  13. int[][] dp = new int[n + 1][edge];
  14. for (int i = 1; i <= n; i++) {
  15. int temp = stones[i - 1];
  16. for (int j = 0; j < edge; j++) {
  17. //记录数组
  18. dp[i][j] = dp[i - 1][j];
  19. if (j >= temp) {
  20. dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - temp] + temp);
  21. }
  22. }
  23. }
  24. return Math.abs(sum - 2 * dp[n][edge-1]);
  25. }

**时间复杂度O(nn)