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

示例 2:

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

提示:

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

题解分析

解法一:深度优先搜索

  1. 本题最简单的解法就是深搜,因为题目要求符合条件的解法,而且每一步有两种不同的选择,这很像走迷宫类型的题目。
  2. 通过设置一个全局变量来存储符合条件的结果,接着使用递归搜索来查找符合条件的组合。
class Solution {
    int ans;
    public int findTargetSumWays(int[] nums, int target) {
        dfs(nums, 0, 0, target);
        return ans;
    }
    private void dfs(int[]nums, int pos, int cur, int target){
        if(pos == nums.length){
            if(cur == target){
                ans++;
            }
            return;
        }
        dfs(nums, pos + 1, cur + nums[pos], target);
        dfs(nums, pos + 1, cur - nums[pos], target);
    }
}

解法二:动态规划

  1. 其实本题仔细看,可以发现这是一道动态规划题,而且是动态规划里面的0-1背包问题。
  2. 假设数组中所有符号为负数的数之和为neg,所有元素之和为sum,那么数组中所有符号为正的数之和为sum-neg,且target = sum - neg - neg,那么可以得到:neg = (sum - target) / 2。所以题目也就是要求数组中是否能够找到一些元素的和为neg,且组合种类有多少种。
  3. 根据0-1背包问题,可以设置一个动态方程dp[i][j]表示前i个数可以组成元素和为j的种数。\(dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]\)
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        // dp[i][j]表示前i个数,满足元素和为j的组合数
        // dp[i][j] = dp[i-1][j] + dp[i][j-nums[i]];
        int n = nums.length;
        // pos = sum - neg, pos - neg = target, sum - neg -neg = target, neg = (sum - target) / 2
        int sum = 0;
        for(int i=0; i<n; i++){
            sum += nums[i];
        }
        int dif = sum - target;
        if(dif < 0 || (dif & 1) == 1){
            return 0;
        }
        target = dif >> 1;
        int[][] dp = new int[n+1][target+1];
        dp[0][0] = 1;
        for(int i=1; i<=n; i++){
            for(int j=0; j<=target; j++){
                if(j < nums[i-1]){
                    dp[i][j] = dp[i-1][j];
                }else{
                    dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i-1]];
                }
            }
        }
        return dp[n][target];
    }
}

解法三:动态规划压缩数组

  1. 考虑到本题也是动态规划,所以可以使用压缩数组的方法来减少数组空间。
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        // dp[i][j]表示前i个数,满足元素和为j的组合数
        // dp[i][j] = dp[i-1][j] + dp[i][j-nums[i]];
        int n = nums.length;
        // pos = sum - neg, pos - neg = target, sum - neg -neg = target, neg = (sum - target) / 2
        int sum = 0;
        for(int i=0; i<n; i++){
            sum += nums[i];
        }
        int dif = sum - target;
        if(dif < 0 || (dif & 1) == 1){
            return 0;
        }
        target = dif >> 1;
        int[] dp = new int[target+1];
        dp[0] = 1;
        for(int i=0; i<n; i++){
            for(int j=target; j>=nums[i]; j--){
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[target];
    }
}

结果展示

image

posted @ 2022-01-04 21:40  Garrett_Wale  阅读(272)  评论(0编辑  收藏  举报