leetcode 416 分割等和子集

简介: leetcode 416 分割等和子集

分割等和子集


e03541d1a5b841fa9c77d591c415e65f.png一个商品如果可以重复多次放入是完全背包,而只能放入一次是01背包,写法还是不一样的。
本题中使用的是01背包,因为元素我们只能用一次。

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

动态背包(二维背包)

dp[ i ][ j ] 中

  • i 是放入背包中元素的范围,从0 - i 中取元素,每个元素取一次。
  • j 是当前背包的容量上限

本题的核心是找到刚好背包容量是sum/2装满的时候。

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum  = 0 , target = 0;
        for(auto it:nums) sum += it;
        //如果和是奇数,就不能分成两个相等的子集
        if(sum%2 == 1) return false; 
        //目标是找到sum/2
        target = sum/2;
        vector<vector<int>> dp(nums.size() , vector<int>(target+1 , 0));
    //背包初始化第一行的值,第一行是只能放第一个元素
    //检查背包的大小能否放进去,能就放进去第一个元素,不能就空着
    //第一列是背包容量是0的时候,dp[i][0]也都是0,不用额外初始化
        for(int j = 1 ; j<=target ;j++  )
            if(j>=nums[0]) dp[0][j] = nums[0];
        //开始遍历
        for(int i=1 ; i<nums.size() ;i++)
        {
            for(int j = 1 ; j<=target ;j++)
            {
              //如果当前值大于背包的容量,就不放进去
                if(j < nums[i]) dp[i][j] = dp[i-1][j];
                //如果可以放进去,就找放进去和不放进去大的一个
                else dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]] + nums[i]);
            }
        }
        //最后在背包大小是sum/2的一列里找,刚好背包装满的
        for(int i=0; i<nums.size();i++)
            if(dp[i][target]==target) return true;
        return false;
    }
};

动态背包+滚动数组(一维背包)

dp[ j ]表示 背包总容量是 j

dp[ j ] = max(dp[ j ], dp[ j - nums[ i ] ] + nums[ i ])

相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。


587de1b64fed48848592e6171bb9fb66.png

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum  = 0 , target = 0;
        for(auto it:nums) sum += it;
        if(sum%2 == 1) return false;
        target = sum/2;
        vector<int> dp(target+1,0);
    //开始遍历
        for(int i=0 ; i<nums.size() ;i++)
        {
          //倒叙背包容量,防止一个值被多次存入
            for(int j=target ; j >= 0 ; j-- )
            {
              //如果当前背包容量可以放入该值
              //就找放进去和不放进去大的一个
                if(j>=nums[i]) 
                  dp[j] = max( dp[j] , dp[j-nums[i]] + nums[i]);
                //如果放不进去,就不变
                else 
                  dp[j] = dp[j];
            }
        }
        //当背包容量是sum/2的时候刚好装满,就认为成功
        if(dp[target] == target) return true;
        else return false;
    }
};

二刷(二维)

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

二刷(一维)

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for(auto it:nums) sum += it;
        if(sum%2 == 1) return false;
        vector<int> dp(sum/2+1,0);
        for(int i=0 ; i<nums.size() ;i++ )
        {
            for(int j=sum/2 ; j>=nums[i]; j--)
            {
                dp[j] = max(dp[j] , dp[j-nums[i]] + nums[i]);
            }
        } 
        if(dp[sum/2] == sum/2) return true;
        return false; 
    }
};
相关文章
|
1月前
|
Java
leetcode-78:子集
leetcode-78:子集
26 1
leetcode-78:子集
|
1月前
|
Go
golang力扣leetcode 416.分割等和子集
golang力扣leetcode 416.分割等和子集
31 0
|
1月前
leetcode-1994:好子集的数目
leetcode-1994:好子集的数目
46 0
|
15天前
|
机器学习/深度学习 存储 算法
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
|
15天前
|
存储 机器学习/深度学习 算法
力扣78题:生成子集
力扣78题:生成子集
|
1月前
|
算法
leetcode代码记录(子集
leetcode代码记录(子集
16 0
|
1月前
|
Go
golang力扣leetcode 90.子集II
golang力扣leetcode 90.子集II
20 1
|
1月前
|
Java
leetcode-90:子集 II
leetcode-90:子集 II
29 1
|
1月前
|
Java
leetcode:698-划分为k个相等的子集
leetcode:698-划分为k个相等的子集
21 0
leetcode:698-划分为k个相等的子集
|
1月前
代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集
代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集
28 0