import java.util.*;

/**
 * NC214 分割等和子集
 * @author d3y1
 */
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return bool布尔型
     */
    public boolean partition (int[] nums) {
        return solution1(nums);
        // return solution2(nums);
    }

    /**
     * 动态规划: 01背包
     *
     * dp[i]表示背包大小为i时所能凑成的最大整数和
     * 
     * dp[j] = Math.max(dp[j], dp[j-nums[i]]+nums[i])  , nums[i]<=j<=v
     *
     * @param nums
     * @return
     */
    private boolean solution1(int[] nums){
        int n = nums.length;

        int sum = 0;
        for(int i=0; i<n; i++){
            sum += nums[i];
        }
        // 所有整数和为奇数
        if(sum%2 == 1){
            return false;
        }

        int v = sum/2;
        int[] dp = new int[v+1];
        for(int i=0; i<n; i++){
            // 某个整数大于一半
            if(nums[i] > v){
                return false;
            }
            // 某个整数等于一半
            if(nums[i] == v){
                return true;
            }
            for(int j=v; j>=nums[i]; j--){
                dp[j] = Math.max(dp[j], dp[j-nums[i]]+nums[i]);
            }
        }

        // 是否能恰好装满
        return dp[v]==v;
    }

    /**
     * 动态规划
     * 
     * dp[i]表示背包大小为i时是否能恰好装满
     * 
     * dp[j] = dp[j] | dp[j-nums[i]]  , nums[i]<=j<=v
     * 
     * @param nums
     * @return
     */
    private boolean solution2(int[] nums){
        int n = nums.length;

        int sum = 0;
        for(int i=0; i<n; i++){
            sum += nums[i];
        }
        // 所有整数和为奇数
        if(sum%2 == 1){
            return false;
        }

        int v = sum/2;
        boolean[] dp = new boolean[v+1];
        dp[0] = true;
        for(int i=0; i<n; i++){
            // 某个整数大于一半
            if(nums[i] > v){
                return false;
            }
            // 某个整数等于一半
            if(nums[i] == v){
                return true;
            }
            for(int j=v; j>=nums[i]; j--){
                dp[j] = dp[j] | dp[j-nums[i]];
            }
        }

        // 是否能恰好装满
        return dp[v];
    }
}