文章目录
- 39 组合总和
- 40 组合总和II
- 216 组合总和 III
39 组合总和
当前sum大于target时,就停止进入解空间树下一层
class Solution {
public:
vector<vector<int>> ans;
vector<int> arr;
int cur_sum;
void func(int start, const vector<int>& candidates, const int target){
if(cur_sum > target){
return;
}
if(cur_sum == target){
ans.push_back(arr);
return;
}
for(int i = start; i < candidates.size(); i++){
arr.push_back(candidates[i]);
cur_sum += candidates[i];
func(i, candidates, target);
cur_sum -= candidates[i];
arr.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
cur_sum = 0;
func(0, candidates, target);
return ans;
}
};
剪枝: 将candidates进行排序,当前sum加上下一个元素大于target时,就不进入解空间树下一层
class Solution {
public:
vector<vector<int>> ans;
vector<int> arr;
int cur_sum;
void func(int start, const vector<int>& candidates, const int target){
if(cur_sum == target){
ans.push_back(arr);
return;
}
for(int i = start; i < candidates.size() && cur_sum + candidates[i] <= target; i++){
arr.push_back(candidates[i]);
cur_sum += candidates[i];
func(i, candidates, target);
cur_sum -= candidates[i];
arr.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
cur_sum = 0;
func(0, candidates, target);
return ans;
}
};
40 组合总和II
由于给定的candidates存在重复元素,还按照39 组合总和
中的算法就会发生上述组合重复的情况,可以看到红框的两个部分完全一样,即不应该生成第二个红框中的节点。同一层节点不允许有重复,如果重复则不应该往下继续生成节点
根据used数组判断是同一树层重复了,还是往下深入时使用了重复的元素,同一数层不允许重复使用元素,但是往下深入时可以使用重复元素
- used[i - 1] == true,说明同一树枝candidates[i - 1]使用过,可以选择
- used[i - 1] == false,说明同一树层candidates[i - 1]使用过,则应该挑选下一个元素,continue
class Solution {
public:
vector<vector<int>> ans;
vector<int> arr;
vector<bool> used;
int cur_sum;
void func(int start, const vector<int>& candidates, const int target){
if(cur_sum == target){
ans.push_back(arr);
return;
}
for(int i = start; i < candidates.size(); i++){
if(i > 0 && candidates[i] == candidates[i-1] && used[i - 1] == false){
continue;
}
if(cur_sum + candidates[i] > target){
break;
}
arr.push_back(candidates[i]);
cur_sum += candidates[i];
used[i] = true;
func(i + 1, candidates, target);
used[i] = false;
cur_sum -= candidates[i];
arr.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
cur_sum = 0;
used.resize(candidates.size(), false);
func(0, candidates, target);
return ans;
}
};
216 组合总和 III
为避免数字重复或组合重复,升序取数字即可,解空间树如下图所示:
根据解空间树翻译出代码:
class Solution {
public:
int cur_sum = 0;
vector<vector<int>> ans;
vector<int> arr;
void func(int i, int start, int k, int n){
if(i == k){
if(cur_sum == n){
ans.push_back(arr);
}
return;
}
// 这里不能是i+1,而应该是start
for(int j = start; j <= 9; j++){
if(cur_sum + j > n){
// 和大于n了,就不再往arr中放数据了,退出for循环,回溯到上一层
break;
}
arr.push_back(j);
cur_sum += j;
func(i + 1, j + 1, k , n);
cur_sum -= j;
arr.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
func(0, 1, k, n);
return ans;
}
};
剪枝方法同LeetCode 77. 组合,最终的目的就是:当前剩余能挑选的元素数量能够满足还需要的元素数量
class Solution {
public:
int cur_sum = 0;
vector<vector<int>> ans;
vector<int> arr;
void func(int i, int start, int k, int n){
if(i == k){
if(cur_sum == n){
ans.push_back(arr);
}
return;
}
// 这里不能是i+1
for(int j = start; j <= 9 - (k - arr.size()) + 1; j++){
if(cur_sum + j > n){
break;
}
arr.push_back(j);
cur_sum += j;
func(i + 1, j + 1, k , n);
cur_sum -= j;
arr.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
func(0, 1, k, n);
return ans;
}
};