target sum java_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.

因为这里涉及到多种不同的选择,所以很容易联想到用dfs,代码如下:

1 classSolution {2 public int findTargetSumWays(int[] nums, intS) {3 int[] count = { 0};4 helper(nums, 0, S, count);5 return count[0];6 }7

8 private void helper(int[] nums, int index, int S, int[] count) {9 if (index == nums.length && S == 0) {10 count[0]++;11 }12 if (index >= nums.length) return;13 helper(nums, index + 1, S +nums[index], count);14 helper(nums, index + 1, S -nums[index], count);15 }16 }

但是这种方法明显是没有优化的,所以时间比其他方法要高。简单的优化就是当我们到了i-th这个位置的时候,如果发现后面部分的值的和或者差都不可能达到target值,我们就应该放弃。

1 public classSolution {2 public int findTargetSumWays(int[] nums, intS) {3 if(nums == null || nums.length == 0) return 0;4

5 int n =nums.length;6 int[] sums = new int[n];7 int[] count = { 0};8 sums[n - 1] = nums[n - 1];9 for (int i = n - 2; i >= 0; i--) {10 sums[i] = sums[i + 1] +nums[i];11 }12 helper(nums, sums, S, 0, count);13 return count[0];14 }15 public void helper(int[] nums, int[] sums, int target, int pos, int[] count){16 if(pos == nums.length && target == 0){17 count[0]++;18 }19

20 if (pos == nums.length) return;21 if (sums[pos] < Math.abs(target)) return;22

23 helper(nums, sums, target + nums[pos], pos + 1, count);24 helper(nums, sums, target - nums[pos], pos + 1, count);25 }26 }

this is a classic knapsack problem

in knapsack, we decide whether we choose this element or not

in this question, we decide whether we add this element or minus it

So start with a two dimensional array dp[i][j] which means the number of ways for first i-th element to reach a sum j

we can easily observe that dp[i][j] = dp[i-1][j+nums[i]] + dp[i-1][j-nums[i],

Another part which is quite confusing is return value, here we return dp[sum+S], why is that?

because dp's range starts from -sum --> 0 --> +sum

so we need to add sum first, then the total starts from 0, then we add S

Actually most of Sum problems can be treated as knapsack problem, hope it helps

1 public int findTargetSumWays(int[] nums, intS) {2

3 int sum = 0;4 for(intn: nums){5 sum +=n;6 }7 if (S < -sum || S > sum) { return 0;}8

9 int[][] dp = new int[nums.length + 1][ 2 * sum + 1];10 dp[0][0 + sum] = 1; //0 + sum means 0, 0 means -sum, check below graph

11 for(int i = 1; i <= nums.length; i++){12 for(int j = 0; j < 2 * sum + 1; j++){13

14 if(j + nums[i - 1] < 2 * sum + 1) dp[i][j] += dp[i - 1][j + nums[i - 1]];15 if(j - nums[i - 1] >= 0) dp[i][j] += dp[i - 1][j - nums[i - 1]];16 }17 }18 return dp[nums.length][sum +S];19 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值