leetcode 力扣 494 目标和

87 阅读1分钟

动态规划,和 416 分割等和子集写法二是一样的。区别在于背包的定义。

  • 设数组nums的和为sum,为了得到target,取其中负数部分的和为negneg是正的,把负号提出来),那么非负整数部分的和为sum - neg,得到
  • target = (sum - neg) - neg = sum - 2 * neg
  • neg = (sum - target) / 2

可以看到dp数组的含义就是,有多少种方法把容量为neg的背包装满? 就找到有多少种组合使目标和为target

特殊情况判断:

  • 根据题目提示0 <= nums[i] <= 1000,所以neg也必须是非负整数。我们取sum - targetdiffneg = diff / 2neg为非负整数,所以diff必须是非负偶数

注意和booleandp的区别,一个最多是+ 0,一个是可能会有false替换true

if (nums[i - 1] <= j) {
     dp[i][j] += dp[i - 1][j - nums[i - 1]];
}
if (num <= j) {
    dp[i][j] = dp[i - 1][j] || dp[i - 1][j - num];
}

1.jpeg

3.jpeg

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        // 先进行特殊情况判断
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }

        int diff = sum - target;
        if (diff < 0 || (diff & 1) == 1) {
            return 0;
        }

        int neg = diff / 2;
        int n = nums.length;

        int[][] dp = new int[n + 1][neg + 1];
        dp[0][0] = 1;

        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= neg; j++) {
                dp[i][j] += dp[i - 1][j];

                if (nums[i - 1] <= j) {
                    dp[i][j] += dp[i - 1][j - nums[i - 1]];
                }
            }
        }

        return dp[n][neg];
    }
}