目标和
494. 目标和
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例:
输入:nums: [1, 1, 1, 1, 1], S: 3 输出:5 解释:
-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
一共有5种方法让最终目标和为3。
提示:
数组非空,且长度不会超过 20 。
初始的数组的和不会超过 1000 。
保证返回的最终结果能被 32 位整数存下。
思路
- 转换成01背包问题
考虑到每个数字不管是取正数还是取负数,都只能取一次,所以考虑使用01背包解决 - 可以转换一下,设有正数值为 x ,那么负数的数值就为 sum-x ,可以列出等式
x-(sum-x) = S
,所以x = (s+sum)/2
问题也就转换成了装满容量为x的背包,有几种方法 也就是说target = bagSize = x - 本题还需特判:当S>sum时,肯定没有方法,如果x不为整数,也不符合题目要求
分五步走:
- 确定dp数组及其下标含义:dp[j]表示装满容量为j的背包的方法数
- 推导dp公式:不考虑nums[i]的情况下,有dp[j-nums[i]]中方法(个人理解不考虑nums[i],相当于nums[i]是一个负数,不算进正数)
考虑到nums[i].就有dp[j]种方法.
所以dp[j] = dp[j] + dp[j-nums[i]]
- 初始化dp数组:dp[0] = 1,因为背包容量为0时,也可以有装入0个物品这一种方法
- 确定遍历方向:dp[j] 由 dp[j-nums[i]] 推出,所以遍历方向是从左往右,先遍历物品,再倒序遍历背包容量
- 举例推导dp数组
代码
public int findTargetSumWays(int[] nums, int S) {
int sum = 0;
for(int i=0;i<nums.length;i++) sum