494. Target Sum

在这里插入图片描述

又是一道背包的题目自己做的很不好,修改了很多次才通过。

最基本的回溯不说了,说说dp的方法。
算出总和,超出的那部分除以二,如果有一些值和为这个值,我们把它们前面置为-,其余为正,就是我们想要的答案。我们找出其中某些数的和等于这个值有多少种情况,答案就是这个。
也就是有一个目标值,对于数组中的每一个,我们讨论取不取它,明显的背包问题。

困难在边角的处理。

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = accumulate(nums.begin(), nums.end(), 0);
        if (sum < S)
            return 0;
        if ((sum - S) & 0x1)
            return 0;
        int target = (sum - S) / 2;
        //if (target == 0)
            //return 1;
        int sz = nums.size();
        vector<vector<int>> dp(sz, vector<int>(target+1, 0));
        if (nums[0] != 0) {
            dp[0][0] = 1;
            if (nums[0] <= target)
                dp[0][nums[0]] = 1;
        } else 
            dp[0][0] = 2;
        for (int i = 1; i < sz; ++i)
            for (int j = 0; j <= target; ++j) {
                if (nums[i] > j)
                    dp[i][j] = dp[i-1][j];
                else 
                    dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]];
            }
        return dp.back().back();
    }
};

困难的是对dp中第0行的处理。
应该还是对自己设的状态理解不够:dp[i][j]:以nums[i]为结尾,目标为j的个数总共有多少个。
那么对于i=0的情况,也就是第一个数,构成目标为0-target的个数分别为多少?具体看代码。这是写的过程中最烦的问题。

另外,自己居然在设dp的大小时犯了糊涂,应该有target+1列的,一开始竟然只设了target列。因为这个列数本身就是target,第j列就是target就为j,所以想要算到target的话,必须得有target+1列。

另外,这一题代码只用了上一行的状态,可想而知它是可以优化为两行甚至一行(这比较难写)的。之后再看看,可以优化一下,参考一下评论区

背包还是得再练练

posted @ 2019-09-18 16:37  于老师的父亲王老爷子  阅读(8)  评论(0编辑  收藏  举报