494. 目标和

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

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

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

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

 

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 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
+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 <= 100

 

从数据看2^20次方搜索数据很极限,适当剪枝应该可以通过,不多说这种解法。

另一个方面看这道题:

存在一个集合A和一个目标数Target,然后存在一个正集合P和一个负集合F,F ∩ P = 空, F U P = A;可以得出一个等式

sum(P) - sum(F) = Target

两边加上sum(P) + sum(F) = sum(A)

sum(P) + sum(F) + sum(P) - sum(F) = Target + sum(A)

2sum(P) = Target + sum(A)

sum(P) = ( Target + sum(A) ) / 2

可以知道Target + sum(A)是个偶数,而且还能知道,如果sum(A)比Target小,那么肯定无法构造出来。

剩下通用情况就简单了,从集合A中选取若干个数组成集合P,sum(p) = ( Target + sum(A) ) / 2固定值

这就把问题转化为了一个01背包问题,背包大小是( Target + sum(A) ) / 2

class Solution 
{
public:
    int findTargetSumWays(vector<int>& nums, int target) 
    {
        int sum = 0;
        for ( auto a : nums ) sum += a;
        if ( ( sum < target ) || ( sum + target ) % 2 == 1 ) return 0;
        int size = ( sum + target ) / 2;
        vector<int> dp( size + 1 );
        dp[0] = 1;
        for ( auto a : nums )
        {
            for ( int i = size; i >= a; --i )
            {
                dp[i] += dp[i - a];
            }
        }
        return dp[size];
    }
};

 

 

 

 

posted on 2021-06-07 10:50  LLawliet  阅读(53)  评论(0编辑  收藏  举报

导航