问题描述
You are given a list of non-negative integers, a1, a2, …, an, and a target, S.
Now you have 2 symbols + and -. For each integer, you should choose one from + and – as its new symbol.
Find out how many ways to assign symbols to make sum of integers equal to target S.
Example 1:
Input: nums is [1, 1, 1, 1, 1], S is 3.
Output: 5
Explanation:
-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 There are 5 ways to assign symbols to make the sum of nums be target 3.
问题分析及算法求解:
1.将数组的值求和得到sum,若sum-S可被2整除,则商即为所有负加数的和,问题可被转化为:
求解数组nums中有多少种组合数的和为目标值target。
否则,返回0;
若sum < abs(S) , 返回0.
2.利用动态规划求解新问题:
2.1 创建一个大小为sum+1的整型数组dp,初始化dp[0]=1,其余为0.
2.2 对于nums中的每一个元素,更改dp数组中相应索引的值。(注意这里需要先将原数组dp拷贝出来)
数组的值即:和为index的组合个数。
2.3 返回dp[target]的值,即为所求。
代码实现
class Solution {
public int findTargetSumWays(int[] nums, int S) {
int res=0;
int sum=0;
for(int x:nums){
sum+=x;
}
int[] dp=new int[sum+1];
dp[0] = 1;
//判断是否有解
if((sum-S)%2 != 0 || sum<Math.abs(S) )
return 0;
int target = (sum-S)/2;//目标值
for(int num:nums){
//需要拷贝原数组,避免多加
int[] array = Arrays.copyOf(dp, dp.length);
for(int i=0;i<array.length;i++){
if(array[i]>0 && i+num<dp.length)
//若已有array[i]种方法可以获得i,现在就有array[i+num]+array[i]种方法获得i+num
dp[i+num] = array[i+num]+array[i];
}
}
return dp[target];
}
}