力扣 1049. 最后一块石头的重量 II(中等)

题目

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

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

最后,最多只会剩下一块石头。返回此石头最小的可能重量 。如果没有石头剩下,就返回 0。
在这里插入图片描述
提示:

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

题解

动态规划求解
和昨天的问题有点相似,昨天是在元素前赋上+、-号,求目标值,可以转化成在数组 n u m s nums nums 中选取若干元素,使得这些元素之和等于 n e g neg neg
今天可以将石头分成两拨,它们的差值就是最终的结果,因此差值尽可能要小。转化为背包问题就是,设总重量为sum, 有一个容量为sum/2的背包,在数组中取若干元素,使得背包装的越满。
这里使用滚动数组节省空间,所以要采取倒序遍历。若采取正序遍历,则在计算当前状态 d p [ j ] dp[j] dp[j]时,上一个状态的 d p [ j − s t o n e [ i ] ] dp[j-stone[i]] dp[jstone[i]]已经被覆盖掉了。因此倒序遍历,可以保证状态转移的一致性。

class Solution {
    // 转换为0-1背包问题,石头总和为sum,每个背包容量为sum / 2,背包装的石头越接近容量越好
    // 这样两个背包的差值越小,最后得到的结果越小
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for(int stone : stones) sum += stone;
        int[] dp = new int[sum / 2 + 1];  //dp[i]表示前i个石头,能装下的最大重量
        for(int stone : stones){
            for(int j = sum / 2; j >= stone; j--){   // 倒序遍历,保证计算中的仍是前一次的状态
                dp[j] = Math.max(dp[j], dp[j - stone] + stone);   
            }
        }
        return sum - 2 * dp[sum / 2];  // 得到差值
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值