目标和题面如下
给定一个整数数组 nums 和一个整数 target 。向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数以构造一个表达式,
例如,nums = [2, 1] , 可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
实例如下:
输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
从题目的字面含义出发,我们使用一个二维数组作为DP数组,该数组的第一维代表数列数组的下标,第二维代表所有可能的目标和,其范围从-total到total, total是数列中所有元素之和。DP[m][n]中的数据就是使用前m个元素可以计算得到n的所有方法的数量,而所有这些方法都可以用于DP[m + 1][n + nums[m+1]]和DP[m + 1][n - nums[m+1]]之中。
使用以上的规律,我们可以根据数列数组的下标从小到大,依次推进,最后返回DP数组中的第一维为数列数组最后一个元素,第二维为target的元素的数值,如下图所示
Java代码如下
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int N = nums.length;
int total = 0;
for (int i = 0; i < N; i ++) {
total += nums[i];
}
if (target > total || target < -total) {
return 0;
}
int[][] dp = new int[N][2 * total + 1];
dp[0][ nums[0] + total] = 1;
//+0 and -0
dp[0][-nums[0] + total] += 1;
for (int i = 1; i < N; i++) {
for (int j = -total; j <= total; j ++) {
if (dp[i - 1][j + total] > 0) {
int x = j + nums[i];
if (x <= total) {
dp[i][x + total] += dp[i - 1][j + total];
}
x = j - nums[i];
if (x >= -total) {
dp[i][x + total] += dp[i - 1][j + total];
}
}
}
}
return dp[N - 1][target + total];
}
}
要注意的是上面代码中为了保证下标有效,DP数组的第二维将需要对应的目标和加上total值,使其范围从[-total, total]转换成[0, 2 * total]。