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; 
    }
};
相关文章
|
3月前
|
算法
LeetCode第90题子集II
LeetCode第90题"子集II"的解题方法,通过排序和回溯算法生成所有不重复的子集,并使用一个boolean数组来避免同一层中的重复元素,展示了解决这类问题的编码技巧。
LeetCode第90题子集II
|
3月前
|
Python
【Leetcode刷题Python】416. 分割等和子集
LeetCode 416题 "分割等和子集" 的Python解决方案,使用动态规划算法判断是否可以将数组分割成两个元素和相等的子集。
29 1
|
3月前
|
Python
【Leetcode刷题Python】131. 分割回文串
LeetCode题目131的Python编程解决方案,题目要求将给定字符串分割成所有可能的子串,且每个子串都是回文串,并返回所有可能的分割方案。
21 2
|
3月前
|
索引 Python
【Leetcode刷题Python】78. 子集
LeetCode题目78的Python编程解决方案,题目要求给定一个互不相同的整数数组,返回该数组所有可能的子集(幂集),且解集中不能包含重复的子集。
22 1
|
3月前
|
算法
LeetCode第78题子集
文章分享了LeetCode第78题"子集"的解法,使用递归和回溯算法遍历所有可能的子集,展示了将子集问题视为树形结构进行遍历的解题技巧。
|
5月前
|
存储 算法 数据可视化
LeetCode 132题详解:使用动态规划与中心扩展法解决分割回文串 II 的最少分割次数问题
LeetCode 132题详解:使用动态规划与中心扩展法解决分割回文串 II 的最少分割次数问题
|
5月前
|
存储 算法 数据可视化
LeetCode 131题详解:高效分割回文串的递归与动态规划方法
LeetCode 131题详解:高效分割回文串的递归与动态规划方法
|
6月前
力扣2578. 最小和分割
力扣2578. 最小和分割
|
5月前
|
机器学习/深度学习 存储 算法
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
|
5月前
|
存储 机器学习/深度学习 算法
力扣78题:生成子集
力扣78题:生成子集