友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

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

思路分析

这道题可以使用 DFS 解决。不过,需要注意的是,只需要保存关键变量即可。另外,也可以增加实例变量。

通过 \(sum = positive + negative\) 和 \(target = positive - negative\) 解方程可以得到 \(positive = (sum + target) / 2\) 和 \(negative = (sum - target) / 2\)。那么,只需要从数字数组中挑选出一些元素使其等于 positivenegative 即可。这就转化成了一个 0/1 背包问题。

  • 一刷

  • 二刷

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
 * Runtime: 3 ms, faster than 90.55% of Java online submissions for Target Sum.
 * Memory Usage: 38.8 MB, less than 10.00% of Java online submissions for Target Sum.
 *
 * Copy from: https://leetcode-cn.com/problems/target-sum/solution/dong-tai-gui-hua-ji-bai-liao-98de-javayong-hu-by-r/[动态规划击败了98%的java用户 - 目标和 - 力扣(LeetCode)]
 *
 * @author D瓜哥 · https://www.diguage.com
 * @since 2020-01-29 21:59
 */
public int findTargetSumWays(int[] nums, int S) {
    int sum = 0;
    for (int num : nums) {
        sum += num;
    }
    if (sum < S || (sum + S) % 2 == 1) {
        return 0;
    }
    int target = (sum + S) / 2;
    int[] dp = new int[target + 1];
    dp[0] = 1;
    for (int num : nums) {
        for (int i = target; i >= num; i--) {
            dp[i] += dp[i - num];
        }
    }
    return dp[target];
}

/**
 * Runtime: 688 ms, faster than 5.06% of Java online submissions for Target Sum.
 * Memory Usage: 39 MB, less than 10.00% of Java online submissions for Target Sum.
 */
private int count = 0;

public int findTargetSumWaysDfs(int[] nums, int S) {
    if (Objects.isNull(nums) || nums.length == 0) {
        return 0;
    }
    findTargetSumWays(nums, S, 0, 0);
    return count;
}

private void findTargetSumWays(int[] nums, int target, int sum, int index) {
    if (index == nums.length) {
        if (sum == target) {
            count++;
        }
    } else {
        int num = nums[index];
        findTargetSumWays(nums, target, sum + num, index + 1);
        findTargetSumWays(nums, target, sum - num, index + 1);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-10-08 17:39:59
 */
public int findTargetSumWays(int[] nums, int target) {
  int sum = Arrays.stream(nums).sum();
  if (sum < Math.abs(target)) {
    return 0;
  }
  if ((sum + target) % 2 == 1) {
    return 0;
  }
  int positive = (sum + target) / 2;
  int negative = (sum - target) / 2;
  int capacity = Math.min(positive, negative);
  int[][] dp = new int[capacity + 1][nums.length + 1];
  dp[0][0] = 1;
  for (int i = 0; i <= capacity; i++) {
    for (int j = 1; j <= nums.length; j++) {
      if (i < nums[j - 1]) {
        dp[i][j] = dp[i][j - 1]; // 数字大于期望值,只能不选
      } else {
        dp[i][j] = dp[i][j - 1] + dp[i - nums[j - 1]][j - 1];
      }
    }
  }
  return dp[capacity][nums.length];
}

思考题

  1. 再推敲一下动态规划的解法;

  2. 学习背包问题!