力扣【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

题解:

方法一:

枚举

import java.util.*;
class Solution {
    int count = 0;
    public int findTargetSumWays(int[] nums, int target) {
        calculate(nums, 0, 0, target);
        return count;
    }
    public void calculate(int[] nums, int i, int sum, int target) {
        if (i == nums.length) {
            if (sum == target) {
                count++;
            }
        } else {
            calculate(nums, i + 1, sum + nums[i], target);
            calculate(nums, i + 1, sum - nums[i], target);
        }
    }
}
/**
 * @author wyl
 */
public class Main {
    public static void main(String[] args) {
        Solution s = new Solution();
        int[] nums = {1,1,1,1,1};
        int target = 3;
        int res = s.findTargetSumWays(nums, target);
        System.out.println(res);
    }
}

方法二:

动态规划——01背包问题

关于背包问题的模板参考这个链接:https://leetcode-cn.com/problems/target-sum/solution/yi-pian-wen-zhang-chi-tou-bei-bao-wen-ti-wa5r/

背包分类的模板:

1、0/1背包:外循环nums,内循环target,target倒序且target>=nums[i];

2、完全背包:外循环nums,内循环target,target正序且target>=nums[i];

3、组合背包:外循环target,内循环nums,target正序且target>=nums[i];

问题分类的模板:

1、最值问题:dp[i] = max/min(dp[i], dp[i-nums]+nums)或dp[i] = max/min(dp[i], dp[i-num]+1);

2、组合问题:dp[i]=dp[i]+dp[i-num];

3、存在问题(bool):dp[i]=dp[i]||dp[i-num];

我们想要的 S = 正数和 - 负数和 = x - y
而已知 x 与 y 的和是数组总和:x + y = sum,得到y = sum - x

列方程求解得到:
可以求出 x = (S + sum) / 2 = target
也就是我们要从 nums 数组里选出几个数,令其和为 target(target 间接给出)。
于是转化为是否可以用 nums 中的数组合和成 target,01 背包问题,外层循环为选择池 nums,内层循环为 target。
dp[i] 表示和为 i 的 num 组合有 dp[i] 种。

外层遍历 nums 每个 num;
内层遍历 target(由大到小)。
对于元素之和等于 i - num 的每一种排列,在最后添加 num 之后即可得到一个元素之和等于 i 的排列,因此在计算 dp[i] 时,应该计算所有的 dp[i − num] 之和。
dp[i] = dp[i] + dp[i - num]
对于边界条件,我们定义 dp[0] = 1 表示只有当不选取任何元素时,元素之和才为 0,因此只有 1 种方案。
最后返回 dp[target]

class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (S > sum || (S + sum) % 2 == 1) {
            return 0;
        }
        int target = (S + sum) / 2;
        int[] dp = new int[target + 1];
        dp[0] = 1;
        for (int i = 0; i < nums.length; i++) {
            for (int j = target; j >= nums[i]; j--) {
                dp[j] = dp[j] + dp[j - nums[i]];
            }
        }
        return dp[target];
    }
}

/**
 * @author wyl
 */
public class Main {
    public static void main(String[] args) {
        Solution s = new Solution();
        int[] nums = {1, 1, 1, 1, 1};
        int target = 3;
        int res = s.findTargetSumWays(nums, target);
        System.out.println(res);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值