力扣416题、1049题(背包,动态规划,数组划分问题)

416.给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

  1. 咋一看觉得还挺不好做,需要找到所有的分割数组的方法,这暴力解法既不好想又不好做。
  2. 看了题解才恍然大悟这可以用解决01背包问题的思路来做。将数组中所有的元素都看作物品,每个元素的值即作为物品的价值,又作为物品的体积来看待,然后将所有元素的值都求和除以2,得到的数作为背包的体积。为什么呢?因为这样做的话,如果数组中有某些元素能够刚好填满这个背包,那么剩下的元素就自然而然地归到了一块,即这个数组可以划分成两个和相等的子集。不过以上想法还漏了一点点细节,那就是当数组的和是奇数的话,那么不管怎么划分都是没有办法得到两个和相等的子集的。
  3. 那么思路有了,代码就是比较常规的01背包代码,这里用一维dp数组来解决问题。
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) {
            sum += nums[i];
        }
        if (sum % 2 == 1)
            return false;
        // 背包体积为数组总和的一半,数组中元素的值作为物品的重量,如果刚好有物品的总和能够恰好达到背包体积,则说明可以将这个数组分割成两个子集
        int bagWeight = sum / 2;
        // dp数组初始化
        vector<int> dp(bagWeight + 1, 0);
        // 遍历每个元素
        for (int i = 0; i < nums.size(); i++) {
            // 当背包体积大于当前元素的值的话,则更新dp数组
            for (int j = bagWeight; j >= nums[i]; j--) {
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }
 
        if (dp[bagWeight] == bagWeight)   
            return true;
        else
            return false;
    }
};

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

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

如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

  1. 再看一下1049题,咋一看跟416题完全是没有任何关系的题,也是一头雾水。看了题解才发现很巧妙,如果能尽量让石头分成重量相同的两堆,那么相撞之后剩下的石头的重量就会最小。那么实际上也就是说这个题跟416题的解法几乎是一模一样的,数组中的每一个元素的值作为一个物品的价值跟体积,然后计算数组总和除以2得到背包的体积。然后用一维dp数组来解决问题,尽可能让背包能够放入价值越大的石头,这样由于背包的体积是石头重量总和的一半,所以也就相当于把石头尽可能的分成了重量相同的两堆。
  2. Java代码如下:
class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for (int i = 0; i < stones.length; i++) {
            sum += stones[i];
        }
        int bagWeight = sum / 2;
        int[] dp = new int[bagWeight + 1];
        for (int i = 0; i < stones.length; i++) {
            for (int j = bagWeight; j >= stones[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
            }
        }
        return sum - 2 * dp[bagWeight];
    }
}
  1. 能够发现,这个题除了对dp[bagWeight]的用法有一点差别之外,几乎跟416题是一样的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值