416. 分割等和子集(0-1背包)

 

难度中等

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

 

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。



首先回忆一下背包问题大致的描述是什么:

给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 wt[i],价值为 val[i],现在让你用这个背包装物品,最多能装的价值是多少?

那么对于这个问题,我们可以先对集合求和,得出 sum,把问题转化为背包问题:

给一个可装载重量为 sum / 2 的背包和 N 个物品,每个物品的重量为 nums[i]。现在让你装物品,是否存在一种装法,能够恰好将背包装满?

 

 

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        sums = sum(nums)
        if sums%2==1:
            return False
        sums = sums//2
        dp = [0] * (sums+1)
        for i in range(len(nums)):
            for j in range(sums+1)[::-1]:
                if j - nums[i]>=0:
                    dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
        return dp[sums]==sums

 

 

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for(auto i : nums) {
            sum+=i;
        }
        if(sum%2==1) return false;
        sum = sum/2;
        int n = nums.size();
        vector<vector<int>> dp = vector<vector<int>>(n+1,vector<int>(sum+1,0));
        for(int i = 1; i < n+1;i++) {
            for(int j = 1; j < sum+1;j++) {
                if (j-nums[i-1]>=0) {
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i-1]] + nums[i-1]);
                } else {
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return dp[n][sum]==sum;
    }
};

 

 

class Solution {
public:
    bool canPartition(vector<int>& nums) {
    int sum = 0, n = nums.size();
    for (int num : nums) sum += num;
    if (sum % 2 != 0) return false;
    int target = sum / 2;
    vector<int> dp(target + 1, 0);
    for (int i = 1; i <=n; i++) 
        for (int j = target; j >= 0; j--) 
            if (j - nums[i-1] >= 0) {
                dp[j] = max(dp[j],dp[j - nums[i-1]]+nums[i-1]);
            } else {
                dp[j] = dp[j];
            }

    return dp[target]==target;
}
};

 

 



class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        int max_num =0;
        for(auto i : nums) {
            sum+=i;
            max_num = max(max_num,i);
        }
        if(sum%2==1) return false;
        
        if (max_num>sum/2) return false;//[1,2,5]
        sum = sum/2;
        int n = nums.size();
        vector<vector<bool>> dp = vector<vector<bool>>(n+1,vector<bool>(sum+1,false));
        //前i个背包,正好装满j的容量
        //dp[..][0] = true
        for(int i = 0;i < n+1;i++) {
            dp[i][0] = true;
        }
        for(int i = 1; i < n+1;i++) {
            for(int j = 1; j < sum+1;j++) {
                if (j-nums[i-1]>=0) {
                    dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]];
                } else {
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return dp[n][sum];
    }
};

 

 

posted @ 2021-10-13 00:10  乐乐章  阅读(46)  评论(0编辑  收藏  举报