1、题目描述
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
2、解题思路
(1)利用暴力回溯
满足条件则向前进一步,否则回溯。
回溯重点!回溯之后要撤销执行回溯函数之前的操作
(2)利用动态规划
3、代码实现
(1)回溯
int sumWays = 0;
int count = 0;
public int findTargetSumWays(int[] nums, int target) {
countSum(nums, target, 0, 0);
return sumWays;
}
public void countSum(int[] nums, int target, int index, int sum) {
//回溯返回条件
if (sum == target && count == nums.length) {
sumWays++;
return;
}
//回溯过程(此处的count记录当前已经放入计算中的nums中的元素个数)
for (int i = index; i < nums.length; i++) {
//加上当前元素
sum += nums[i];
count++;
countSum(nums, target, i + 1, sum);
//回溯之后撤销操作
sum -= nums[i];
count--;
//减去当前元素
count++;
sum -= nums[i];
countSum(nums, target, i + 1, sum);
sum += nums[i];
count--;
}
}
(2)动态规划
/**
* 动态规划
* (1)dp[i][j]:加上或减去nums[i]后,和为j的方案数,最终找到i=nums.length,j为target的方案数
* (2)递推式:dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]]:表示下一行的可行方法数依赖于上一行 + 和 - 该位置的num值对应的方法数
*/
public int findTargetSumWays(int[] nums, int target) {
int len=nums.length;
if(len==0){
return 0;
}
int sum=0;
for (int i = 0; i < len; i++) {
sum+=nums[i];
}
//数组中所有数相加都没有target大,则必然不存在所有数的组合=target的情况
if(Math.abs(target)>sum){
return 0;
}
// 声明动态规划数组
int[][] dp=new int[len][sum*2+1];
// 因为0+0、0-0均为0
if(nums[0]==0){
dp[0][sum]=2;
}else{
dp[0][sum-nums[0]]=1;
dp[0][sum+nums[0]]=1;
}
//这里超过边界值变为0:因为最边界的情况表示所有值取全正或全负,所以不到最后一个nums的值时,该位置是不会有数的
int left=0,right=0;
for (int i = 1; i <nums.length ; i++) {
for (int j = 0; j < sum*2+1; j++) {
left=(j-nums[i]>=0)?j-nums[i]:0;
right=(j+nums[i]<sum*2+1)?j+nums[i]:0;
dp[i][j]=dp[i-1][left]+dp[i-1][right];
}
}
return dp[len-1][sum+target];
}