题目链接
英文链接:https://leetcode.com/problems/target-sum/
中文链接:https://leetcode-cn.com/problems/target-sum/
题目详述
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 +
和 -
。对于数组中的任意一个整数,你都可以从 +
或 -
中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例 1:
1 | 输入: nums: [1, 1, 1, 1, 1], S: 3 |
注意:
- 数组的长度不会超过20,并且数组中的值全为正数。
- 初始的数组的和不会超过1000。
- 保证返回的最终结果为32位整数。
题目详解
方法一:DFS。
1 | public class LeetCode_00494 { |
上面的递归调用存在很多重复的子过程,我们可以利用缓存把子过程的结果保存下来。
方法二:记忆化搜索。
- 因为初始的数组的和不会超过 1000,所以数据的可能范围为 [-1000, 1000]。
- 运用缓存数组需要加上偏移量 1000 来保证下标非负。
1 | public class LeetCode_00494 { |
方法三:动态规划。
- 本问题可以转化为 Subset Sum 问题。
- Subset Sum 问题可以运用 01背包 来解决。
可以将数组分为两部分,P 和 N,其中 P 使用正号,N 使用负号,推导过程如下:
1 | sum(P) - sum(N) = target |
因此问题就转化为了 Subset Sum 问题:在给定的集合中找到子集元素加和等于 (target + sum(nums)) / 2 的方法总数。
1 | public class LeetCode_00494 { |
实际上,LeetCode416-分割等和子集 也是一个Subset Sum 问题。只不过它不需要求方法总数,只需要判断存在性。