目标和
难度:
标签:
题目描述
给你一个非负整数数组 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
代码结果
运行时间: 41 ms, 内存: 16.1 MB
/*
题目思路:
可以用Java Stream来实现。我们将数组元素转换成其正负两种形式的数组,然后通过flatMap操作来合并两种可能性。
然后,使用collect(Collectors.toList())收集所有可能的组合。最后,通过stream().filter()来筛选出所有满足条件的组合。
*/
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Solution {
public int findTargetSumWays(int[] nums, int target) {
List<Integer> sums = Arrays.stream(nums)
.boxed()
.flatMap(num -> Arrays.asList(num, -num).stream())
.collect(Collectors.toList());
return (int) findCombinations(sums, 0, 0, target);
}
private long findCombinations(List<Integer> nums, int index, int currentSum, int target) {
if (index == nums.size() / 2) {
return currentSum == target ? 1 : 0;
}
return findCombinations(nums, index + 1, currentSum + nums.get(index * 2), target)
+ findCombinations(nums, index + 1, currentSum + nums.get(index * 2 + 1), target);
}
}
解释
方法:
这个题解使用动态规划的思路来解决目标和问题。首先计算数组nums的总和total_sum,如果目标值target的绝对值大于总和或者(target + total_sum)不能被2整除,则无解返回0。否则,将问题转化为在nums中选择一些数,使得它们的和等于(target + total_sum) / 2。创建一个动态规划数组dp,其中dp[i]表示选择nums中的数,使得它们的和等于i的方案数。初始化dp[0]=1,表示当目标和为0时,只有一种方案,即什么都不选。然后遍历nums中的每个数num,对于每个可能的和j,更新dp[j] += dp[j-num],表示在之前的方案数的基础上,加上选择当前数num得到和为j的方案数。最终返回dp[target_sum],即达到目标和的方案总数。
时间复杂度:
O(n * target_sum)
空间复杂度:
O(target_sum)
代码细节讲解
🦆
如何确定(target + total_sum) % 2 == 1时题目无解?这个条件是怎样得出的?
▷🦆
动态规划数组dp的每个元素代表了什么意义?为什么初始化dp[0]为1?
▷🦆
为什么在更新dp数组时需要从target_sum开始向下遍历到num-1,而不是从0向上遍历?
▷🦆
当nums数组中包含0时,这种动态规划方法是否需要做特殊处理?如果需要,如何处理?
▷相关问题
给表达式添加运算符
给定一个仅包含数字 0-9
的字符串 num
和一个目标值整数 target
,在 num
的数字之间添加 二元 运算符(不是一元)+
、-
或 *
,返回 所有 能够得到 target
的表达式。
注意,返回表达式中的操作数 不应该 包含前导零。
示例 1:
输入: num =
"123", target = 6
输出: ["1+2+3", "1*2*3"]
解释: “1*2*3” 和 “1+2+3” 的值都是6。
示例 2:
输入: num =
"232", target = 8
输出: ["2*3+2", "2+3*2"]
解释: “2*3+2” 和 “2+3*2” 的值都是8。
示例 3:
输入: num =
"3456237490", target = 9191
输出: []
解释: 表达式 “3456237490” 无法得到 9191 。
提示:
1 <= num.length <= 10
num
仅含数字-231 <= target <= 231 - 1