416. 分割等和子集

416. 分割等和子集

难度中等537收藏分享切换为英文接收动态反馈

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

注意:

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

示例 1:

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

输出: true

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

示例 2:

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

输出: false

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

思路:我们可以巧妙的将问题转化为0-1背包问题(即和的一半的大小最多能拿到多大的值)

package LeetCode;

/**
 * @ClassName Q416
 * @Description TODO
 * @Author m
 * @Version 1.0
 */
public class Q416 {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }

        if((sum & 1) == 1) {
            return false;
        }

        int target = sum/2;

        /**
         * dp[i][j]表示0~i的数中是否能选出一定的数和为j
         * 则结果即为dp[nums.length-1][target]
         */
        boolean[][] dp = new boolean[nums.length][target+1];

        for (int i = 0; i < dp.length; i++) {
            dp[i][0] = true;
        }

        if(nums[0] <= target){
            dp[0][nums[0]] = true;
        }


        for (int i = 1; i < dp.length; i++) {
            for (int j = 1; j < dp[i].length; j++) {
                //可以发现这里的dp[i][j]只与上一层有关,可以将空间复杂度优化为O(target)
                dp[i][j] = dp[i-1][j];
                if(nums[i] <= j) {
                    dp[i][j] |= dp[i-1][j-nums[i]];
                }
            }
        }

        return dp[nums.length-1][target];

    }

    public static void main(String[] args) {
        System.out.println(new Q416().canPartition(new int[]{
                100
        }));
    }

}

因为我喜欢追寻过程中的自己
原文地址:https://www.cnblogs.com/IzuruKamuku/p/14359737.html