1、题目描述:
2、思路:
这道题首先一看,好像可以使用回溯搜索法,把所有的情况找出来,然后相加看是不是为target,若是,则计数器加1。这种思想很朴素,但是,会超时。但是也需要会编写程序啊,我把官方的贴过来吧。是C++代码。
下面是官方给的回溯法的思路:
class Solution {
public:
int count = 0;
int findTargetSumWays(vector<int>& nums, int target) {
backtrack(nums, target, 0, 0);
return count;
}
void backtrack(vector<int>& nums, int target, int index, int sum) {
if (index == nums.size()) {
// 到达边界,说明一次遍历完了
if (sum == target) {
// 符合条件
count++; // 计数器加一
}
} else {
backtrack(nums, target, index + 1, sum + nums[index]); // 第一种情况:前面添加+
backtrack(nums, target, index + 1, sum - nums[index]); // 第二种情况:前面添加-
}
}
};
下面,看看动态规划的思路。需要转化问题。
原问题等同于: 找到nums一个正子集P和一个负子集N,使得总和等于target。即sum(P) - sum(N) == target,
即sum(P) + sum(N) + sum(P) - sum(N) == sum(P) + sum(N) + target
即2 * sum(P) == target + sum(nums), 其中target + sum(nums)必须>=0且为偶数,否则等式不可能成立。
则问题转换为:存在多少个子集P,使sum(P) == (target + sum(nums))/2。
(到达这一步的时候,发现就是找组合啊,所以这里还可以使用回溯法求组合,代码在下面)
那动态规划是怎么做的呢?
dp[i][j]表示从0-i的数中取数,放到和为j的背包中,刚好能填满j的总共的取法有多少种。
(