1 题目
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例 1:
输入: nums: [1, 1, 1, 1, 1], S: 3
输出: 5
解释:
-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
一共有5种方法让最终目标和为3。
注意:
数组非空,且长度不会超过20。
初始的数组的和不会超过1000。
保证返回的最终结果能被32位整数存下。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/target-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2 Java
2.1 方法一(回溯递归)
class Solution {
public int findTargetSumWays(int[] nums, int S) {
if(nums.length == 0){
if(S == 0) return 1;
return 0;
}
function(nums, S, 0, 0);
return ans;
}
// 记录结果
int ans = 0;
// 回溯递归
public void function(int[] nums, int S, int index, int curS){
// if判断 是否符合条件,若符合则计入结果
if(index == nums.length){
if(curS == S) ans++;
return;
}
// for循环 多路选择
function(nums, S, index + 1, curS + nums[index]);
function(nums, S, index + 1, curS - nums[index]);
}
}
2.2 !方法二(动归迭代,背包问题)
class Solution {
public int findTargetSumWays(int[] nums, int S) {
// dp[i][j] 代表 当加减到nums的索引i这个元素(包括该元素),结果为j的方案数量
// 创建dp,初始化
int[][] dp = new int[nums.length][2001];
dp[0][nums[0] + 1000] = 1;
dp[0][- nums[0] + 1000] += 1; // 神坑!!!如果nums[0]是0,则这两行都是dp[0][1000],所以应该是dp[0][1000] = 2
// 外层for 状态步进
for(int i = 1; i < nums.length; i++){
// 内层for 多路择优
for(int j = -1000; j < 1001; j++){
// 需要判断索引是否溢出,即该值是否可达(题目说了nums元素和 <= 1000)
if(j + 1000 - nums[i] >= 0 ) dp[i][j + 1000] += dp[i - 1][j + 1000 - nums[i]];
if(j + 1000 + nums[i] < 2001) dp[i][j + 1000] += dp[i - 1][j + 1000 + nums[i]];
}
}
return S > 1000 ? 0 : dp[nums.length - 1][S + 1000];
}
}