LeetCode 416. 分割等和子集

题目描述

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

注意:

  1. 每个数组中的元素不会超过 100
  2. 数组的大小不会超过 200

示例1:

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

输出: true

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

示例2:

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

输出: false

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum

思路解析

  1. 遍历数组nums,计算得到数组和为\(S\),最大值为\(m\)
  2. \(S\)为奇数,或\(m > S / 2\)`,返回false,记\(target = S / 2\)
  3. \(f(i, j)\)表示区间\([0,i]\)内选择有限个数字,其和能否为\(j\),若能,则\(f(i, j) = T\),否则\(f(i, j) = F\),其中\(i \in [0, n - 1], j \in [0, target]\)
  4. 易知:\(f(i,0) = T\)\(f(0,nums[j]) = T\)
  5. 转移方程:

\[\begin{align*} & f(i,j) = f(i - 1, j) || f(i - 1, j - nums[i])\quad (j >= nums[i]) \\ & f(i,j) = f(i - 1, j)\quad (j < nums[i]) \end{align*} \]

代码实现

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        if(nums.size() < 2)
            return false;
        int sum = 0;
        int max = 0;
        for(auto num : nums) {
            sum += num;
            max = (max > num) ? max : num;
        }
        if(sum % 2)
            return false;
        int target = sum / 2;
        if(max > target)
            return false;
        int imax = nums.size();
        int jmax = target + 1;
        vector<vector<bool>> subs(imax, vector<bool>(jmax, false));
        for(int i = 0; i < imax; i++)
            subs[i][0] = true;
        subs[0][nums[0]] = true;
        
        for(int j = 1; j < jmax; j++) {
            for(int i = 1; i < imax; i++) {
                if(j < nums[i])
                    subs[i][j] = subs[i - 1][j];
                else {
                    subs[i][j] = (subs[i - 1][j - nums[i]] || subs[i - 1][j]);
                }
            }
        }
        
        return subs[imax - 1][jmax - 1];
    }
};
posted @ 2020-10-13 17:26  行者橙子  阅读(103)  评论(0编辑  收藏  举报