题目描述

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

题解

由题可知,数组nums非空,所以分割后的两个子集也必然非空,由于都是正整数,所以nums中元素之和必然为偶数。

这道题是典型的 01 背包问题,假设$dp[i][j]$表示nums中前$i$个元素是否包含和为$j$的子集,那么:

  1. nums[i] = j的时候,dp[i][j] = true
  2. nums[i] > j的时候,dp[i][j] = dp[i - 1][j]
  3. nums[i] < j的时候,dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]
#include <vector>
#include <numeric>

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