【LeetCode-416】分割等和子集

问题

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

示例

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

解答1:背包问题模版

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

重点思路

本题的重点为如何将问题转化为01背包问题。两个子集元素和相同,可将本问题转化为是否存在一个元素子集,使得其加和为总体的一半。我们可以将本问题继续转化为背包问题的经典形式:求满足该容量下,能装下的最大的价值是多少。本问题中价值为该元素自身的值。当最后背包容量为总元素加和的一半,且该背包被装满了,那么满足题目要求。

解答2:更简洁的状态方程

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;
        sum /= 2;
        bool dp[sum + 1]; memset(dp, 0, sizeof(dp));
        dp[0] = true;
        for (int i = 0; i < n; i++)
            for (int j = sum; j >= nums[i]; j--) 
                    dp[j] |= dp[j - nums[i]];
        return dp[sum];
    }
};

重点思路

根据方法1中的分析可知,当背包在上一个阶段没有被装满,那当前阶段也不可能被装满,所以能直接使用一个布尔值来表示最终结果。

posted @ 2021-04-02 14:01  tmpUser  阅读(61)  评论(0编辑  收藏  举报