力扣416. 分割等和子集

 二维数组版本:

class Solution {
    public boolean canPartition(int[] nums){
        //数组要被分成两个,并且元素和相等,转化为背包问题:
//所有物品总重量为sum(数组元素和),现在有两个容量都为sum/2的背包,问这两个背包是否能被刚好装满,
//进一步简化:问其中一个背包能否被刚好装满(一个满了,另一个肯定也能刚好满)
        int sum = 0;
        for(int num: nums){
            sum += num;
        }

        //因为每个物品重量都是正整数,所以sum/2不为整数我们就不可能找到合适的方案。
        if(sum%2!=0)return false;

        int capacity = sum/2;//一个背包的容量

         boolean[][] dp = new boolean[nums.length][capacity+1];//dp[i][j]:一共有i件物品,每件物品重量就是nums对应的元素值,现在用一个容量为j的背包,能否将这些物品装完
         for(int j=1;j<dp[0].length;j++){//第一行要初始化
            if(nums[0]==j){
                dp[0][j] = true;
                break;
            }
         }
         for(int i=1;i<dp.length;i++){
             for(int j=1;j<dp[0].length;j++){//第一列没有实际意义
                if(j-nums[i]>=0)//当前这件物品装得下
                    dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]];//前者拿,后者不拿,不管拿或不拿只要能满足条件就行
                else{
                    dp[i][j] = dp[i-1][j];//装不下就只能不拿了
                }
             }
         }
         return dp[dp.length-1][dp[0].length-1];

    }
}

一维数组版本:

使用一维数组做这道题,我个人感觉就像是在参加拍卖会,比如对于力扣上的第一个例子:

nums = [1,5,11,5]

拍卖会一共有4轮,第一轮物品价值和价格(重量)都为1,第二轮物品价值和价格为5,第三轮物品价值和价格为11,第四轮物品价值和价格为5,我一共带了11元钱(sum/2也即背包容量),拍卖会每一轮我都可以选择买或不买,我的目的是把这11元钱刚好用完。

class Solution {
    public boolean canPartition(int[] nums){
        //使用一维数组外循环就是一次次去更新dp表,每次都会多一件物品要被考虑
        int sum = 0;
        for(int num: nums){
            sum += num;
        }

        //因为每个物品重量都是正整数,所以sum/2不为整数我们就不可能找到合适的方案。
        if(sum%2!=0)return false;

        int capacity = sum/2;//一个背包的容量

        boolean[] dp = new boolean[capacity+1];

        if(nums[0]<dp.length)//初始化
            dp[nums[0]] = true;

        //一维数组内循环要倒序,否则前面的位置会被重复使用
        for(int i=1;i<nums.length;i++){
             for(int j=dp.length-1;j>=nums[i];j--){
                dp[j] = dp[j]||dp[j-nums[i]];//dp[j]:当前这轮不拿,dp[j-nums[i]]:当前这轮拿
             }
         }
         return dp[dp.length-1];

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值