题目:
代码(首刷看解析 2024年2月26日)
思路:根据题意,设两个背包,packageA存放前面是"+"的数字之和,packageB存放前面是“-”的数字之和
则sum = packageA + packageB;
target = packageA - packageB;
则根据以上算式可得packageA = (sum + target)/2;
因为sum和target根据题目都已知,则问题变成求可以放哪些数使得和 == packageA--即动态规划01背包问题
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int& num :nums) {
sum += num;
}
if (sum < abs(target)) return 0;
int tmp = sum + target;
if (tmp % 2 == 1) return 0;
int x = tmp / 2;
vector<int> dp(x + 1, 0);
dp[0] = 1;
for (int i = 0; i < nums.size(); ++i) {
for (int j = x; j >= nums[i]; --j) {
dp[j] += dp[j - nums[i]];
}
}
return dp[x];
}
};
代码(二刷看解析 2024年7月9日 go)
// 设正数和为 left 负数和为 right, 有left + right = sum, left - right = target,可得left = (sum + target)/2
// 则问题可以改为:在nums数组里符合和等于left的子集的数量有多少
// 可以进一步抽象为01背包,背包容量left,物品种类nums,物品的重量和价值都nums[i]
func findTargetSumWays(nums []int, target int) int {
sum := 0
for _,v := range nums {
sum += v
}
if (sum + target) % 2 != 0 {
return 0
}
if target > sum || -target > sum {
return 0
}
left := (sum + target) / 2
// 1. dp[j]表示正数和为j的方法有多少种
// 2. 递推公式:dp[j] = dp[j] + dp[j - nums[i]]
dp := make([]int, left + 1)
// 3. 初始化:dp[0] = 1
dp[0] = 1
// 4. 遍历顺序,先容量再物品,容量左到右,物品右到左
for i := 0; i < len(nums); i++ {
for j := left; j >= nums[i]; j-- {
dp[j] += dp[j - nums[i]]
}
}
return dp[left]
}