dp[0] 赋值为 1 的写法
1秒记住
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum=0;
for(int i=0; i<nums.length; i++){
sum+=nums[i];
}
// 如果nums={998},target=-999
// 显然凑不出来,所以得用target的绝对值去比较sum
if(Math.abs(target)>sum){
return 0;
}
// 因为 left 是个整数,2*left=sum+target
// 所以 target+sum 必然是个偶数
if((target+sum)%2 != 0){
return 0;
}
int bagSize=(sum+target)/2;
int[] dp=new int[bagSize+1];
dp[0]=1;
for(int i=0; i<nums.length; i++){
for(int j=bagSize; j>=nums[i]; j--){
dp[j]+=dp[j-nums[i]];
}
}
return dp[bagSize];
}
}
dp[0]不赋值为1的写法
思考方向是:不是背包容量为 0 时只能装 0 件物品也算一种装法,而是背包容量 j 等于 nums[i] 的时候,只能装下该物品,也就是只有一种装法。
这种思路下,我们就要考虑 0 ,因为 0 太特殊了,它可以无消耗的装 2 次,也就是 +0 和 -0,因此数组中有多少个 0 ,我们的结果就应该乘 2 的( 0 的个数)的次方
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum=0;
for(int i=0; i<nums.length; i++){
sum+=nums[i];
}
// 如果nums={998},target=-999
// 显然凑不出来,所以得用target的绝对值去比较sum
if(Math.abs(target)>sum){
return 0;
}
// 因为 left 是个整数,2*left=sum+target
// 所以 target+sum 必然是个偶数
if((target+sum)%2 != 0){
return 0;
}
int bagSize=(sum+target)/2;
int[] dp=new int[bagSize+1];
// 用来记录数组中0的个数
int num=0;
for(int i=0; i<nums.length; i++){
if(nums[i]==0){
num++;
}
for(int j=bagSize; j>=nums[i]; j--){
if(nums[i]!=0){
// 背包容量 j 等于nums[i]的时候,
// 只能装下该物品,也就是只有一种装法
if(j==nums[i]){
dp[j]+=1;
continue;
}
// 当前要装的数字为 nums[i]
// 那么一共的装法就是 dp[j-nums[i]]时的装法
dp[j]+=dp[j-nums[i]];
}
}
}
if(Math.abs(target)==sum){
// [1, 0] 1 这种情况,结果就是 2 的 0 的个数的次方
// [0, 0, 0] 0 也同样的
return 1*(int)Math.pow(2, num);
}
// 结果应该乘 2 的( 0 的个数)的次方
return dp[bagSize]*(int)Math.pow(2, num);
}
}
不把 dp[0] 赋值为 1 会多很多操作,
所以 dp[0] 就简单认为装背包容量为 0 的背包只有一种装法,因为我们需要用到这个 dp[0] 的值,所以 dp 数组长度必须取为 bagSize+1 ,不然只能像我上面那样麻烦的写了