力扣 494. 目标和

力扣 494. 目标和

image.png

image.png

这道题可以这样理解:target是由数组里的某些数字加上+号或-号然后求和得到。所以target也等于数组里一些数字减去另一些数字得到的结果。把数组里面前面是正号的元素之和设为left,前面是负号的元素之和设为right,left-right==left-(sum-left)==target。left=( target+sum(nums[i]) )/2。问题就转化为:求装满容量为left的背包,有多少种方法。

动态规划的五个步骤:

  1. 设dp[j]表示填满容量为j的背包,有dp[j]种方法。
  2. 当前的dp[j]等于上一次循环的dp[j]加上dp[j-nums[i]],即dp[j]=dp[j]+dp[j-nums[i]]。
  3. 由递推公式得知,dp[0]=1,其他元素初始化成0,若dp[0]也设为0,递推到后面每个dp[j]都是0,不符合实际情况。
  4. 先遍历物品,然后遍历背包容量。倒序遍历背包容量。
  5. 手写一下推导每个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];
    }
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注