力扣 494. 目标和
这道题可以这样理解:target是由数组里的某些数字加上+号或-号然后求和得到。所以target也等于数组里一些数字减去另一些数字得到的结果。把数组里面前面是正号的元素之和设为left,前面是负号的元素之和设为right,left-right==left-(sum-left)==target。left=( target+sum(nums[i]) )/2。问题就转化为:求装满容量为left的背包,有多少种方法。
动态规划的五个步骤:
- 设dp[j]表示填满容量为j的背包,有dp[j]种方法。
- 当前的dp[j]等于上一次循环的dp[j]加上dp[j-nums[i]],即dp[j]=dp[j]+dp[j-nums[i]]。
- 由递推公式得知,dp[0]=1,其他元素初始化成0,若dp[0]也设为0,递推到后面每个dp[j]都是0,不符合实际情况。
- 先遍历物品,然后遍历背包容量。倒序遍历背包容量。
- 手写一下推导每个dp[j]的过程。
需要注意当target绝对值大于sum(nums[i]),没有方法得到target。当sum(nums[i])+target是奇数,也没有方法得到target。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum=0;
for(int i=0; i<nums.length;i++){
sum+=nums[i];
}
if(sum<Math.abs(target))return 0;
if((target+sum)%2!=0)return 0;
int left=(target+sum)/2;
int[] dp=new int[left+1];
dp[0]=1;
for(int i=0; i<nums.length; i++){
for(int j=left; j>=nums[i]; j--){
dp[j]+=dp[j-nums[i]];
}
}
return dp[left];
}
}