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

    注意:
    每个数组中的元素不会超过 100
    数组的大小不会超过 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

    思路:
    典型01背包问题,令 dp[i][j] 表示从前 i 个元素中挑选一些正整数,使其和为 j 的真假,对于nums[i]
    dp[i][j] =dp[i-1] || dp[i][j-nums[i]]
    可以看出每一行的状态只与上一行有关,可以用滚动数组优化空间复杂度:
    dp[j] |= dp[j-nums[i]]
    复杂度分析
    时间复杂度O(n*target) target 为数组元素和的一半
    空间复杂度O(target)

    1. var canPartition = function(nums) {
    2. if(nums.length<2) return false;
    3. let max=0
    4. let sum = nums.reduce((prev,val)=>{
    5. max =Math.max(max,val)
    6. return prev+val
    7. },0)
    8. if(sum % 2 !== 0) return false;
    9. let target = sum/2;
    10. if(target<max) return false;
    11. let dp = new Array(target+1).fill(false)
    12. dp[0]=true;
    13. for(let i = 0; i < nums.length; i++){
    14. for(let j = target;j>=nums[i];j--){
    15. dp[j] |= dp[j-nums[i]];
    16. }
    17. }
    18. return dp[target]
    19. };