416. 分割等和子集

题目

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

实现

分析

本题可以采用动态规划方法解决,参考01背包问题。
要求集合里是否有sum/2的子集

  • 背包的体积为sum/2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 若背包装满,证明集合中存在sum/2的子集
  • 元素不可重复放入

动态规划:

  1. 确定dp[j] 含义:dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]。
  2. 找递推公式:
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  1. dp数组初始化:非0下标的元素初始化为0
  2. 确定遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历。
  3. 推到dp数组:
dp[j]的数值一定是小于等于j的。

如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。

代码

class Solution {
    public boolean canPartition(int[] nums) {
        int len = nums.length;
        int dp[] = new int[10001];
        int sum =  Arrays.stream(nums).sum();
        if(sum %2 ==1){
            return false;
        }
        int target = sum/2;
        
        for(int i=0;i<len;i++){
            for(int j=target;j>=nums[i];j--){
                dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
            }
        }
        if(target!=dp[target]){
            return false;
        }
        return true;
    }
}

你可能感兴趣的:(算法,算法,leetcode,动态规划)