leetcode 494. Target Sum
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.
Note:
The length of the given array is positive and will not exceed 20.
The sum of elements in the given array will not exceed 1000.
Your output answer is guaranteed to be fitted in a 32-bit integer.
solution
approach 1 动态规划
将数组分成两部分,一部分全为正其和为 P,另一部分全为负其和为(-Q)
P-Q=target
P+Q+P-Q=target+Q+P
2P=target+(P+Q)=target+sum(all)
P=(taget+sum(all))/2
P的值知道了问题就转化为了,从数组中选择若干个数使其和为P,一共有多少种选法?
令A[n][P]为从第一个到第n个中,选择若干个和为P的选法种数;从而其动态规划的状态转移方程为
A[n][P]=A[n-1][P]+A[n-1][P-a[n]]
对于第n个数a[n]来说,如果不选前面的和也为P,那么对于不选a[n],其选法就有A[n-1][p]种,如果选择了a[n]的情况,那么此种选法就有A[n-1][P-a[n]]种选法;
初始化:当p等于0时,即一个都不选是一种情况,对于第一个数来说,只有P=a[1]时有一种选择的情况
注意:当一个数字为零是那么可以选择也可以不选择,应该有两种选法
class Solution {
public:
int findTargetSumWays(vector& nums, int S) {
int n = nums.size();
int sum = 0;
for (int i = 0; i < n; i++)
sum += nums[i];
if (S > sum || (sum + S) % 2 != 0)
return 0;
int cap = (sum + S) / 2;
int dp[n + 1][sum + 1];
for (int i = 1; i <= n; i++)
for (int j = 0; j <= cap; j++)
if (j == 0)
if (nums[i - 1] == 0)
dp[i][j] = 2;
else
dp[i][j] = 1;
else
dp[i][j] = 0;
if (nums[0] != 0)
dp[1][nums[0]] = 1;
else
dp[1][nums[0]] = 2;
//print("%d",dp[1][1])
for (int i = 2; i <= n; i++)
for (int j = 0; j <= cap; j++)
{
int left = j - nums[i - 1];
int tmp = 0;
if (left >= 0)
{
tmp = dp[i - 1][left];
}
dp[i][j] = dp[i - 1][j] + tmp;
}
return dp[n][cap];
}
};
参考链接
leetcode