一、题目
给你一个整数数组nums和一个整数target 。
向数组中的每个整数前添加'+'或' - ',然后串联起所有整数,可以构造一个表达式:
例 如 , nums=[2,1] , 可 以 在 2 之 前 添 加 '+' , 在 1 之 前 添 加 ' - ' , 然 后串联起来得到表达式"+2-1"。
返回可以通过上述方法构造的、运算结果等于target的不同表达式的数目
二、求解思路
动态规划解决
递推公式如下
if ( j >= num ) { //不选num和选num
dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[ i - 1 ][ j - num ];
} else { //不能选择num
dp[ i ][ j ] = dp[ i - 1 ][ j ];
}
三、代码实现
通过上面的分析,我们再来看下最终代码
#include <iostream>
#include <vector>
int findTargetSumWays(std::vector<int>& nums, int target) {
int length = nums.size();
// 求数组中所有数字的和
int sum = 0;
for (int num : nums) {
sum += num;
}
// 如果所有数字的和小于target,或者sum - target是奇数,
// 说明无论怎么添加符号,表达式的值都不可能是target
if (sum < target || ((sum - target) & 1) != 0) {
return 0;
}
// 我们要找到一些元素让他们的和等于capacity的方案数即可。
int capacity = (sum - target) >> 1;
// dp[i][j]表示在数组nums的前i个元素中选择一些元素,
// 使得选择的元素之和等于j的方案数
std::vector<std::vector<int>> dp(length + 1, std::vector<int>(capacity + 1, 0));
// 边界条件
dp[0][0] = 1;
for (int i = 1; i <= length; i++) {
for (int j = 0; j <= capacity; j++) {
// 动态规划公式
if (j >= nums[i - 1]) { // 不选第i个和选第i个元素
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
}
else { // 不能选择第i个元素
dp[i][j] = dp[i - 1][j];
}
}
}
// 从数组前length个(也就是全部)元素中选择一些元素,让他们的
// 和等于capacity的方案数。
return dp[length][capacity];
}
// 这里粘贴之前的 findTargetSumWays 函数定义
int main() {
std::vector<int> nums = { 1, 1, 1, 1, 1 }; // 示例数组
int target = 3; // 目标和
int result = findTargetSumWays(nums, target); // 调用函数计算方案数
std::cout << "Number of ways to reach target sum: " << result << std::endl;
return 0;
}
时间复杂度:O(n* capacity),n是数组的长度。
空间复杂度:O(n* capacity),capacity是( sum- target) /2。
我们看到上面二维数组计算的时候,当前那一行的值只和上一行的有关,所以我们可以改成一维数组,这里要注意嵌套中的第二个for循环要倒叙遍历。因为改成一维数组之后,数组后面的值要依赖前面的(改变之前的),如果从前往后遍历,前面的值被修改了,会导致后面的运行结果错误。如果倒叙,也就是先计算数组后面的值,因为前面的还没有计算,也就是还没有被修改,所以不会导致结果错误。来看下代码
代码优化:
#include <vector>
int findTargetSumWays(std::vector<int>& nums, int target) {
int length = nums.size();
// 求数组中所有数字的和
int sum = 0;
for (int num : nums) {
sum += num;
}
// 如果所有数字的和小于target,或者sum - target是奇数,
// 说明无论怎么添加符号,表达式的值都不可能是target
if (sum < target || ((sum - target) & 1) != 0) {
return 0;
}
// 我们要找到一些元素让他们的和等于capacity的方案数即可。
int capacity = (sum - target) >> 1;
std::vector<int> dp(capacity + 1, 0);
// 边界条件
dp[0] = 1;
for (int i = 0; i < length; i++) {
// 注意,这里要倒序
for (int j = capacity; j >= nums[i]; j--) {
// 动态规划公式
dp[j] += dp[j - nums[i]];
}
}
return dp[capacity];
}
// Main 函数的示例
int main() {
std::vector<int> nums = {1, 1, 1, 1, 1}; // 示例数组
int target = 3; // 目标和
int result = findTargetSumWays(nums, target); // 调用函数计算方案数
std::cout << "Number of ways to reach target sum: " << result << std::endl;
return 0;
}
时间复杂度:O(n* capacity)
空间复杂度:O(capacity)