「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
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
解析
/**
* @brief 动态规划
* 转换为01背包问题
* 例如当我们的 target 不为 −sum 和 sum 时,−sum 和 sum 就是两个对「目标状态」不可达的“额外”状态值,到达 −sum 或 sum 已经使用所有数值,对 target 不可达。
* 我们可以从哪些数值使用哪种符号来分析,即划分为【负值部分】和【非负值部分】。
* 假设非负值为 x, 负值总和为 -(sum - x )
* 所以我们需要求得是: x + (-(sum-x)) = x - (sum-x) = target
* x = (target+sum) / 2
* 此时问题转为:装满容量为x的背包,有几种方法。
*
* 动态规划四部曲:
* 1、确定dp数组以及下标含义
* dp[j] : 填满容量为j的背包,有dp[j]种方法
*
* 2、确定递推公式
* dp[j]的来源:
*
* 填满容量为 j -nums[i]的背包, 有 dp[j-nums[i]]种方法
*
* 举例:
* nums[i] = 2
* dp[3] , 填满背包容量为3的话,有 dp[3] 种方法
* 那么只需要搞到一个2 (nums[i] , 有dp[3]中方法可以凑齐容量为3的背包)
*
*/
代码
class SolutionDP
{
public:
int findTargetSumWays(vector<int> &nums, int target)
{
// 求和
int sum = 0;
for (int num:nums)
{
sum += num;
}
// 没有解决方案
if (abs(target) > sum ||(target + sum) % 2 == 1 )
return 0;
int bagSize = (target + sum) / 2;
vector<int> dp(bagSize + 1, 0);
dp[0] = 1;
// 先遍历物品
for (int i = 0; i < nums.size(); i++)
{
// 再遍历背包
for (int j = bagSize; j >= nums[i]; j--)
{
dp[j] += dp[j - nums[i]];
}
}
return dp[bagSize];
}
};