LeetCode-494. 目标和

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

代码

class Solution {
public:
    /*
        思路:假设有解,其中前边填‘+’号的元素的和为x,nums所有元素的总和为sum,则前边填‘-’号的元素数量有sum-x个,
              则target = x-(sum-x)--->x = (target+sum)/2,因为x代表元素个数,所以必须是整数-->当(target+sum)%2 == 1时返回false(0)
              ##因为target和sum都是定值,所以x(前边填‘+’号的元素的和)也是定值,
                                    所以就可以转化为背包问题:从这些数中能选出多少种和为x的方法

              开一个f[nums.size()+1][x + 1]的数组,f[i][j]表示前i个元素能凑齐j的个数,

              
              
    */
    /*
        此题也是可以用滚动数组将空间复杂度从n*bigPage-->bigPage,但这题只要是考解题思路,这样写易于读者思考
    */
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        int n = nums.size();
        int i,j;
        for(i=0;i<n;i++){
            sum+=nums[i];
        }
        if( (target+sum)%2 )return 0;
        if(abs(target) > sum )return 0; //这一步是防止target为负数,且-target>sum,这种情况也是没有结果的
        
        int bigPage = (sum+target)/2;
        vector<vector<int>> f(n+1,vector<int>(bigPage+1));
        f[0][0] = 1;    //前0个元素凑齐0的次数为1
        for(i=1;i<=n;i++){
            for(j=0;j<=bigPage;j++){
                f[i][j] = f[i-1][j];    //假设nums[i]前边加的‘-’号,这里就等于f[i-1][j]
                if(j - nums[i-1]>=0){   假设nums[i]前边加的‘+’号,则要在前i-1个元素中找f[i-1][j-nums[i-1]]的值,且需要判断下标越界
                    f[i][j] += f[i-1][j-nums[i-1]];  
                } 
            }
        }
        
        return f[n][bigPage];
    }
};

执行结果:
通过

执行用时:
16 ms, 在所有 C++ 提交中击败了48.16%的用户
内存消耗:
12.1 MB, 在所有 C++ 提交中击败了13.82%的用户
通过测试用例:
139 / 139

你可能感兴趣的:(LeetCode刷题,c++,数据结构,动态规划,算法,01背包)