LeetCode416. 分割等和子集

☆☆☆☆☆思路:转化为0-1背包问题。 即,是否可以从输入数组中挑出一些正整数,使得这些数的和 等于 整个数组和的一半。

  本题与传统0-1背包问题的不同在于,传统0-1 背包问题要求 选取的物品的重量之和 不能超过 背包的容量;而本题选取的数字之和需要 恰好等于 规定的和的一半。

  这一点的区别,决定了初始化时,所有值应为False。因此,本题状态转移方程为 F(i, c) = F(i - 1, c) || F(i - 1, c - w(i) ), 其中F(n , c)表示 考虑将n个物品填满容量为C的背包。时间复杂度为 O(n * sum/2) = O(n * sum)

 

  Step1.状态定义:dp[i][j] 表示从数组的[0,i]下标范围内,选取若干正整数,是否存在一种选取方案使得被选取的正整数的和等于j, 初始时均为false。

  Step2.考虑边界情况:

    1. 如果不选取任何正整数,则被选取的正整数为0.因此,dp[i][0] = true

    2.当i==0时,只有一个正整数nums[0]可以选取,因此,dp[0][nums(0)] = true。

  Step3.状态转移:

  

0-1背包,即数组中的元素不可重复使用。技巧为 nums放在外循环,target在内循环,且内循环倒序。

class Solution {
    public boolean canPartition(int[] nums) {
        int n = nums.length;
        if (n < 2) return false;
        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
        boolean[][] dp = new boolean[n][target + 1]; // 背包容量 0 ~ target
        for (int i = 0; i < n; i++) {
            dp[i][0] = true; // 不选取任何正整数,则被选取的正整数和为0
        }
        if (nums[0] <= target) {
            dp[0][nums[0]] = true;
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= target; j++) {
                dp[i][j] = dp[i-1][j];
                if (j >= nums[i]) {
                    dp[i][j] |= dp[i-1][j-nums[i]];
                }
            }
        }
        return dp[n-1][target];
        */
        /**
         *  空间优化
         */
        int target = sum / 2;
        boolean[] dp = new boolean[target + 1];
        dp[0] = true;
        // 只考虑第一个num,看是否能填满对应的背包。
        if (nums[0] <= target) {
            dp[nums[0]] = true;
        }
//        for (int i = 0; i <= target; i++) {
//            dp[i] = (nums[0] == i);
//        }
        for (int i = 1; i < n; i++) {
            for (int j = target; j >= nums[i]; j--) { // 注意要倒序计算
                dp[j] = dp[j] || (dp[j-nums[i]]);
            }
        }
        return dp[target];
    }
}

 

posted @ 2021-01-03 16:33  不学无墅_NKer  阅读(115)  评论(0编辑  收藏  举报