动态规划,和 416 分割等和子集 的写法二是一样的。区别在于背包的定义。
- 设数组
nums的和为sum,为了得到target,取其中负数部分的和为neg(neg是正的,把负号提出来),那么非负整数部分的和为sum - neg,得到 target = (sum - neg) - neg = sum - 2 * neg。neg = (sum - target) / 2
可以看到dp数组的含义就是,有多少种方法把容量为neg的背包装满? 就找到有多少种组合使目标和为target。
特殊情况判断:
- 根据题目提示
0 <= nums[i] <= 1000,所以neg也必须是非负整数。我们取sum - target为diff,neg = diff / 2,neg为非负整数,所以diff必须是非负偶数。
注意和boolean型dp的区别,一个最多是+ 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];
}
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];
}
}