@Leetcode
本题与Leetcode216 组合总和III以及LeetCode77 Combinations的区别是,集合里面的元素可以重复使用,故
递归没有层数限制
,只要选取元素总和为target
,即可返回。而另外两个知道得递归k
层,因为要取k
个元素的集合。(candidates内元素不重复)
回溯三步曲
- 递归函数参数
void generateSum(vector<int>& candidates, int target, int startIndex, int &sum, vector<int> &p)
- 终止条件
if(sum == target){
res.push_back(p);
return;
}
- 单层搜索过程
for(int i = startIndex; i < candidates.size(); i++){
if(sum + candidates[i] <= target){
p.push_back(candidates[i]);
sum = sum + candidates[i];
generateSum(candidates, target, i, sum, p);//不用i+1了,表示可以取重复的数(与combination的区别之处)
sum = sum - candidates[i];
p.pop_back();
}
}
全部代码:
class Solution {
private:
int sum = 0;
vector<vector<int>> res;
void generateSum(vector<int>& candidates, int target, int start, int &sum, vector<int> &p){
if(sum == target){
res.push_back(p);
//cout<<p[0]<<":"<<endl;
//for(int i = 0; i < p.size(); i++)
//cout<<p[i];
//p[0] = true;
//cout<<endl;
//cout<<"return1"<<endl;
return;
}
for(int i = start; i < candidates.size() && sum + candidates[i] <= target; i++){
p.push_back(candidates[i]);
sum = sum + candidates[i];
generateSum(candidates, target, i, sum, p);//不用i+1了,表示可以取重复的数(与combination的区别之处)
sum = sum - candidates[i];
p.pop_back();
}
return;
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
res.clear();
vector<int> p;
sort(candidates.begin(), candidates.end());
generateSum(candidates, target, 0, sum, p);
return res;
}
};
提醒自己:
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void backtracking(vector<int> candidates, int target, int startIndex, int sum){
if(sum == target){
res.push_back(path);
return;
}
//
//!不行 排序了才能用这个条件!!!
for(int i = startIndex; i < candidates.size()
&& sum + candidates[i] <= target; i++){
//if(sum + candidates[i] > target) break;
path.push_back(candidates[i]);
backtracking(candidates, target, i, sum + candidates[i]);
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
res.clear();
path.clear();
sort(candidates.begin(), candidates.end());
backtracking(candidates, target, 0, 0);
return res;
}
};```
![在这里插入图片描述](https://img-blog.csdnimg.cn/a37bff6b246642f5aae3bfe892cac497.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmVsbHlfQmVsaWV2ZXI=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
> 由题意可知,正的数和负的数相加为target,设正的数和为left,元素总和为sum,则有
>left - (sum - left) = targrt
>则left = (sum + target) / 2
>有两种无法构造的情况:
>1. target的绝对值大于sum
>2. target和sum一奇一偶(如若sum为奇数,则说明nums中有奇数个奇数,但是只有偶数个奇数做加减法才能得到一个偶数,故此时无法通过加减法得到target,sum为偶数时同理)
回溯法:
```cpp
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {
if (sum == target) {
result.push_back(path);
}
// 如果 sum + candidates[i] > target 就终止遍历
for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i + 1);
sum -= candidates[i];
path.pop_back();
}
}
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (S > sum) return 0; // 此时没有方案
if ((S + sum) % 2) return 0; // 此时没有方案,两个int相加的时候要各位小心数值溢出的问题
int bagSize = (S + sum) / 2; // 转变为组合总和问题,bagsize就是要求的和
// 以下为回溯法代码
result.clear();
path.clear();
sort(nums.begin(), nums.end()); // 需要排序
backtracking(nums, bagSize, 0, 0);
return result.size();
}
};
动态规划
装满容量为bagSize的背包,有多少种方法
- 确定dp数组及其下标的含义
dp[j]: 填满大小为j的背包的方法数- 确定递推公式
dp[j] = dp[j] + dp[j - nums[i]] (当遍历到nums[i]时,dp[j]就等于没给nums[i]时装满容量j背包的方法数加上装满j - nums[i]容量背包的方法数(此时装入nums[i]就装满容量了))。- dp数组初始化
dp[0] = 1 装满容量为0的背包,有1种方法,即什么都不装
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (abs(S) > sum) return 0; // 此时没有方案
if ((S + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (S + 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];
}
};