416. 分割等和子集(DP)

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

注意:

每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2:

输入: [1, 2, 3, 5]

输出: false

解释: 数组不能分割成两个元素和相等的子集.

分析:

转换0-1背包(0-1背包是无序,完全背包是有序),组合数之和是背包的体积而不是背包中的最大价值,所有dp[][]中的信息为true或false,每个元素当作背包中的一个物品,只能用一次,代码如下:

class Solution {
    
    
public:
    bool canPartition(vector<int>& nums) {
    
    
        int length = nums.size();
        int sum = 0;
        for(int i = 0; i < length; i++){
    
    
            sum += nums[i];
        }
        if((sum & 1) == 1) return false;
        int target = sum / 2;
        // 初始化二维数组,target为取出一些元素组合成的目标值,数组中的每个元素表示能否组合成该值
        vector<vector<int>> dp(length, vector<int>(target + 1, 0)); // 考虑从 0 - target 这 target + 1 个
        // 单独处理下第一行的nums[0]这个位置的元素,将其置为true
        if(nums[0] < target) dp[0][nums[0]] = true;
        // 开始正式的动态规划
        // 从第一行开始
        for(int i = 1; i < length; i++){
    
    
            for(int j = 0; j < target + 1; j++){
    
    
                if(j > 0){
    
    
                    // 随着j向右移动有三种情况
                    if(j < nums[i]) dp[i][j] = dp[i - 1][j];
                    else if(j == nums[i]) dp[i][j] = true;
                    else dp[i][j] = dp[i - 1][j] | dp[i - 1][j - nums[i]];
                }else{
    
    // 第0列,及target为0的时候,不管nums[i]为多少都可以满足
                    dp[i][j] = false;
                }
            }
        }
        return dp[length - 1][target];
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_34612223/article/details/113818205