目标和

Category Difficulty Likes Dislikes
algorithms Medium (49.15%) 1083 -

Tags Companies 给你一个整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

  1. 输入:nums = [1,1,1,1,1], target = 3
  2. 输出:5
  3. 解释:一共有 5 种方法让最终目标和为 3
  4. -1 + 1 + 1 + 1 + 1 = 3
  5. +1 - 1 + 1 + 1 + 1 = 3
  6. +1 + 1 - 1 + 1 + 1 = 3
  7. +1 + 1 + 1 - 1 + 1 = 3
  8. +1 + 1 + 1 + 1 - 1 = 3

示例 2:

输入:nums = [1], target = 1
输出:1

提示:

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

题解:

那么只要搞到nums[i]的话,凑成dp[j]就有dp[j - nums[i]] 种方法。

例如:dp[j],j 为5,

  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 dp[5]。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 dp[5]。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 dp[5]
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 dp[5]
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 dp[5]

那么凑整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。

class Solution {
public:
    //01背包的变形就是二分,要或者不要
    //这里最重要的是找到背包的容量是多少
    //把加法和减法分开,背包装的加的和或者减的和
    //加的和x,减的和sum-x,x-(sum-x)=target,得到x=(target+sum)/2
    //这道题变成了用dp求装满x的种类
    //dp[i]的定义是i的容量内,有dp[i]种方法 ,而不是dp[i]表示最大加到的数最后统计,这样会没法统计
    //dp[i]可以做选择,也可以用来统计
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) sum += nums[i];
        //去掉不存在的情况
        if((sum+target)%2==1) return 0; //加起来的和必须是整数
        //题目给出nums中的数都是正数,
        if(sum<abs(target)) return 0; //全加或者全减都不够使
        int x=(sum+target)/2;
        vector<int> dp(x+1,0); //这里其实只用x的容量大小就够了,
        dp[0]=1; //这个非常重要
        for (int i = 0; i < nums.size(); i++){
            for (int j = x; j>=nums[i]; j--)
            {
                dp[j]=dp[j-nums[i]]+dp[j]; //其实就是统计dp[j-nums[i]]的总数
            }
        }
        return dp[x];
    }
};