思路:看似是回溯遍历问题,其实是0-1背包问题,使用动态规划解决最好。
加法总和x,那么减法总和为sum-x。
x-(sum-x) =target,也就可以推出x=(sum+target)/2
public class FindTargetSumWays {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
// 求出数组的总和
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
// 不能被整除的话,方法是无解的,例如sum=5,target=2
if ((target+sum)%2!=0){
return 0;
}
/***
* 推导步骤:
* step1: left+right = sum
* step2: left-right = target
* step3: left = (sum+target)/2 此时就将这个问题转换为填充满left(x)有几种填充方案,也就是变成了一个0-1背包问题了
*/
int size = (target+sum)/2;
// 为了便于后续计算,将负的size转换为正的
if (size<0){
size=-size;
}
int[] dp = new int[size+1]; // step1:次数数组的含义是:填满j这么大的背包,dp[j]有几种解法
// 初始化,也就是装载容量为0的背包,有一种方法,就是啥也不装
dp[0] = 1;
/**
* 使用动态数组解0-1背包问题,注意点:j从后往前遍历且能取到nums[i]
* */
for (int i = 0; i < nums.length; i++) {
for (int j = size; j >= nums[i]; j--) {
// step2:确定递归公式
dp[j] += dp[j-nums[i]];
}
}
return dp[size];
}
}