LeetCode 494 目标和

题目链接:LeetCode 494 目标和

题目大意:

题解:

回溯

可以使用回溯的方法遍历所有的表达式,回溯过程中维护一个计数器\(count\),当遇到一种表达式的结果等于目标数\(target\)时,将\(count\)的值加\(1\)。遍历完所有的表达式之后,即可得到结果等于目标数\(target\)的表达式的数目。

class Solution {
private:
    int cnt = 0;

public:
    int findTargetSumWays(vector<int>& nums, int target) {
        dfs(nums, target, 0, 0);
        return cnt;
    }

    void dfs(vector<int>& nums, int target, int index, int sum) {
        if (index == nums.size()) {
            if (sum == target) {
                cnt++;
            }
        } else {
            dfs(nums, target, index + 1, sum + nums[index]);
            dfs(nums, target, index + 1, sum - nums[index]);
        }
    }
};

动态规划

参考自LeedCode官方题解
记数组元素和为\(sum\),添加\(-\)号的元素和为\(neg\),则可得到表达式:

\[(sum - neg) - neg = sum - 2 \times neg = target \]

\[neg = \frac{sum - target}{2} \]

由于数组中都是非负整数,所以\(neg\)也必须是非负整数,因此\(sum - target\)必须是非负偶数,若不符合条件可直接返回\(0\)
若上式成立,问题转化成在数组\(nums\)中选取若干元素,使得这些元素之和等于\(neg\),计算选取元素的方案数。我们可以使用动态规划的方法求解。
\(dp[i][j]\)表示在数组\(nums\)的前\(i\)个数中选取元素,使得这些元素之和等于\(j\)的方案数。
状态转移方程:

\[\left\{ \begin{array}{l} dp[i][j] = dp[i - 1][j],j<nums[i] \\ dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]], j \geq nums[i] \end{array} \right. \]

边界条件为\(dp[0][0] = 1\)
由于\(dp\)的每一行的计算只和上一行有关,因此可以使用滚动数组的方式,去掉\(dp\)的第一个维度,将空间复杂度优化到\(O(neg)\)

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        int temp = sum - target;
        if (temp < 0 || temp & 1) {
            return 0;
        }
        temp >>= 1;
        vector<int> dp(temp + 1);
        dp[0] = 1;
        for (int num : nums) {
            for (int j = temp; j >= num; --j) {
                dp[j] += dp[j - num];
            }
        }
        return dp[temp];
    }
};
posted @ 2022-02-04 15:04  ZZHHOOUU  阅读(39)  评论(0编辑  收藏  举报