LeetCode-494. 目标和
题目来源
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
题解分析
解法一:深度优先搜索
- 本题最简单的解法就是深搜,因为题目要求符合条件的解法,而且每一步有两种不同的选择,这很像走迷宫类型的题目。
- 通过设置一个全局变量来存储符合条件的结果,接着使用递归搜索来查找符合条件的组合。
class Solution {
int ans;
public int findTargetSumWays(int[] nums, int target) {
dfs(nums, 0, 0, target);
return ans;
}
private void dfs(int[]nums, int pos, int cur, int target){
if(pos == nums.length){
if(cur == target){
ans++;
}
return;
}
dfs(nums, pos + 1, cur + nums[pos], target);
dfs(nums, pos + 1, cur - nums[pos], target);
}
}
解法二:动态规划
- 其实本题仔细看,可以发现这是一道动态规划题,而且是动态规划里面的0-1背包问题。
- 假设数组中所有符号为负数的数之和为neg,所有元素之和为sum,那么数组中所有符号为正的数之和为sum-neg,且target = sum - neg - neg,那么可以得到:neg = (sum - target) / 2。所以题目也就是要求数组中是否能够找到一些元素的和为neg,且组合种类有多少种。
- 根据0-1背包问题,可以设置一个动态方程dp[i][j]表示前i个数可以组成元素和为j的种数。\(dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]\)。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
// dp[i][j]表示前i个数,满足元素和为j的组合数
// dp[i][j] = dp[i-1][j] + dp[i][j-nums[i]];
int n = nums.length;
// pos = sum - neg, pos - neg = target, sum - neg -neg = target, neg = (sum - target) / 2
int sum = 0;
for(int i=0; i> 1;
int[][] dp = new int[n+1][target+1];
dp[0][0] = 1;
for(int i=1; i<=n; i++){
for(int j=0; j<=target; j++){
if(j < nums[i-1]){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i-1]];
}
}
}
return dp[n][target];
}
}
解法三:动态规划压缩数组
- 考虑到本题也是动态规划,所以可以使用压缩数组的方法来减少数组空间。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
// dp[i][j]表示前i个数,满足元素和为j的组合数
// dp[i][j] = dp[i-1][j] + dp[i][j-nums[i]];
int n = nums.length;
// pos = sum - neg, pos - neg = target, sum - neg -neg = target, neg = (sum - target) / 2
int sum = 0;
for(int i=0; i> 1;
int[] dp = new int[target+1];
dp[0] = 1;
for(int i=0; i=nums[i]; j--){
dp[j] += dp[j-nums[i]];
}
}
return dp[target];
}
}