1.题目描述:
给你一个整数数组nums和一个整数target。向数组中的每个整数前添加'+'或'-',然后串联起所有整数,可以构造一个表达式:例如,nums = [2, 1],可以在2之前添加'+',在1之前添加'-',然后串联起来得到表达式"+2-1"。返回可以通过上述方法构造的、运算结果等于target的不同表达式的数目。
2.递归:类似回溯算法的写法。
class Solution {
private int res = 0;
public int findTargetSumWays(int[] nums, int target) {
dfs(nums, 0, target, 0);
return res;
}
public void dfs(int[]nums, int i, int target, int curVal){
if (i == nums.length) {
if (curVal == target) res++;
return;
}
dfs(nums, i + 1, target, curVal + nums[i]);//i即用来记录数量,又用来遍历数组
dfs(nums, i + 1, target, curVal - nums[i]);
}
}
3.动态规划:
转化为01背包,无论数组元素前面的正负符号怎么变,始终可以通过移项和添加括号转变为left - right的表达式并且left和righ全为和。于是有:left - right = target;left + right = sum;推出left = (target + sum)/ 2。即转化为元素和为left的组合种类个数,也可以用之前的回溯算法求。下面是动态规划解法:
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int ele : nums) sum += ele;
if ((sum + target) % 2 == 1) return 0;
int left = (sum + target) / 2;
if (left < 0) left = -left;//计算总数不影响
int gZise = nums.length;
int[] dp = new int[left + 1];//dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
dp[0] = 1;//关键
for (int i = 0; i < gZise; i++) {
for (int j = left; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];//能放下nums[i]的数目即为前面不放nums[i]的数目,然后叠加
}
}
return dp[left];
}
}