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:
刚开始想到用之前的df0s但是超时
public int findTargetSumWays(int[] nums, int S) {
if (nums == null || nums.length == 0)
return 0;
int res[] = new int[1];
dfsCore(nums, 0, 0, 0, S, res);
return res[0];
}
private void dfsCore(int[] nums, int sum, int idx, int k,
int target, int[] res) {
if (k == nums.length) {
if (sum == target)
res[0] += 1;
return;
}
for (int i = idx; i < nums.length; i++) {
dfsCore(nums, sum + nums[i], i + 1, k + 1, target, res);
dfsCore(nums, sum - nums[i], i + 1, k + 1, target, res);
}
}
之后找到解决方法,因为多用了for循环,导致超时
public int findTargetSumWays(int[] nums, int S) {
int[] arr = new int[1];
helper(nums, S, arr, 0, 0);
return arr[0];
}
public void helper(int[] nums, int S, int[] arr, int sum, int start) {
if (start == nums.length) {
if (sum == S) {
arr[0]++;
}
return;
}
// 这里千万不要加for循环,因为我们只是从index0开始
helper(nums, S, arr, sum - nums[start], start + 1);
helper(nums, S, arr, sum + nums[start], start + 1);
}
public class Solution {
public int findTargetSumWays(int[] nums, int S) {
if (nums == null || nums.length == 0) {
return 0;
}
return helper(nums, S, 0, 0, 0);
}
// 这里不传入全局变量count的原因是每次的count都已返回值形式返回
public int helper(int[] nums, int S, int
sum, int index, int count) {
if (index == nums.length) {
if (sum == S) {
count++;
}
return count;
}
return helper(nums, S, sum + nums[index],
index + 1, count)
+ helper(nums, S, sum - nums[index],
index + 1, count);
}
}
来源discuss:https://discuss.leetcode.com/topic/76245/java-simple-dfs-with-memorization
public class Solution {
public int findTargetSumWays(int[] nums, int S) {
if (nums == null || nums.length == 0) {
return 0;
}
return helper(nums, 0, 0, S, new HashMap<>());
}
private int helper(int[] nums, int index, int sum,
int S, Map map) {
// 避免数字是重复,无法找到截断点
String encodeString = index + "->" + sum;
if (map.containsKey(encodeString)) {
return map.get(encodeString);
}
if (index == nums.length) {
if (sum == S) {
return 1;
} else {
return 0;
}
}
int curNum = nums[index];
int add = helper(nums, index + 1, sum - curNum, S, map);
int minus = helper(nums, index + 1, sum + curNum, S, map);
map.put(encodeString, add + minus);
return add + minus;
}
}
来源http://blog.csdn.net/hit0803107/article/details/54894227
【问题分析】
1、该问题求解数组中数字只和等于目标值的方案个数,每个数字的符号可以为正或负(减整数等于加负数)。
2、该问题和矩阵链乘很相似,是典型的动态规划问题
3、举例说明: nums = {1,2,3,4,5}, target=3, 一种可行的方案是+1-2+3-4+5 = 3
该方案中数组元素可以分为两组,一组是数字符号为正(P={1,3,5}),另一组数字符号为负(N={2,4})
因此: sum(1,3,5) - sum(2,4) = target
sum(1,3,5) - sum(2,4) + sum(1,3,5) + sum(2,4) = target + sum(1,3,5) + sum(2,4)
2sum(1,3,5) = target + sum(1,3,5) + sum(2,4)
2sum(P) = target + sum(nums)
sum(P) = (target + sum(nums)) / 2
由于target和sum(nums)是固定值,因此原始问题转化为求解nums中子集的和等于sum(P)的方案个数问题
4、求解nums中子集合只和为sum(P)的方案个数(nums中所有元素都是非负)
该问题可以通过动态规划算法求解
举例说明:给定集合nums={1,2,3,4,5}, 求解子集,使子集中元素之和等于9 = new_target = sum(P) = (target+sum(nums))/2
定义dp[10]数组, dp[10] = {1,0,0,0,0,0,0,0,0,0}
dp[i]表示子集合元素之和等于当前目标值的方案个数, 当前目标值等于9减去当前元素值
当前元素等于1时,dp[9] = dp[9] + dp[9-1]
dp[8] = dp[8] + dp[8-1]
...
dp[1] = dp[1] + dp[1-1]
当前元素等于2时,dp[9] = dp[9] + dp[9-2]
dp[8] = dp[8] + dp[8-2]
...
dp[2] = dp[2] + dp[2-2]
当前元素等于3时,dp[9] = dp[9] + dp[9-3]
dp[8] = dp[8] + dp[8-3]
...
dp[3] = dp[3] + dp[3-3]
当前元素等于4时,
...
当前元素等于5时,
...
dp[5] = dp[5] + dp[5-5]
最后返回dp[9]即是所求的解
public class Solution {
public int findTargetSumWays(int[] nums, int S) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
if (S > sum || (sum + S) % 2 == 1)
return 0;
return subsetSum(nums, (sum + S) / 2);
}
private int subsetSum(int[] nums, int S) {
int[] dp = new int[S + 1];
dp[0] = 1;//C(0,0)=1
for (int i = 0; i < nums.length; i++) {
for (int j = S; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[S];
}
}