Leetcode 416. 分割等和子集 背包问题变种 动态规划

 

 

/*
 * @lc app=leetcode.cn id=416 lang=cpp
 *
 * [416] 分割等和子集
 *
 * https://leetcode-cn.com/problems/partition-equal-subset-sum/description/
 *
 * algorithms
 * Medium (49.73%)
 * Likes:    761
 * Dislikes: 0
 * Total Accepted:    122.1K
 * Total Submissions: 245.5K
 * Testcase Example:  '[1,5,11,5]'
 *
 * 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
 * 
 * 
 * 
 * 示例 1:
 * 
 * 
 * 输入:nums = [1,5,11,5]
 * 输出:true
 * 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
 * 
 * 示例 2:
 * 
 * 
 * 输入:nums = [1,2,3,5]
 * 输出:false
 * 解释:数组不能分割成两个元素和相等的子集。
 * 
 * 
 * 
 * 
 * 提示:
 * 
 * 
 * 1 
 * 1 
 * 
 * 
 */

思路:

labuladong

可以转化为背包问题,即,能否得到sum/2

dp[i][j]表示使用0-(i-1)的物品,得到和为j.

base状态为dp[i][0]=true,因为sum=0肯定都可以实现

dp[i][j]=dp[i-1][j](不放入nums[i])|dp[i-1][j-nums[i]](放入nums[i])

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

进阶:

状态压缩:dp[i][j]都是通过上一行dp[i-1][..]转移过来的,之前的数据都不会再使用了

所以,我们可以进行状态压缩,将二维dp数组压缩为一维

只在一行dp数组上操作,i每进行一轮迭代,dp[j]其实就相当于dp[i-1][j],所以只需要一维数组就够用了。

唯一需要注意的是j应该从后往前反向遍历,因为每个物品(或者说数字)只能用一次,以免之前的结果影响其他的结果

也就是i=n时,dp[j]为n-1的状态,又因为更新状态时需要用到dp[j-nums[i-1]],所以从后往前更新状态,保证用到dp时是i-1的原值,而不是更新后的值

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

 

posted @ 2021-04-29 17:31  鸭子船长  阅读(112)  评论(0编辑  收藏  举报