Combination Sum 系列
Combination Sum 系列
一次性把 Combination Sum 有关问题都做了一遍,对回溯搜索穷举又有了更加深刻的理解,在此总结
核心思想
递归选择后回溯当前选择,这在组合穷举搜寻的题目中都非常有用
void Sum(int begin, vector<T> path, vector<T> candi, ...) {
if(满足穷举结束条件) return;
// 搜索一遍范围中的所有元素
foreach(i=begin...N) {
// 选择这个元素
path.push_back(candi[i]);
// Sum(..) 继续递归调用继续推进搜索
path.pop_back(); // 回溯
}
}剩下的就是模板一般的套用即可
// Combination Sum
// 题目描述:待选择的数组是无重复的,但是允许重复选择
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
calSum(candidates, 0, target);
return res;
}
void calSum(vector<int>& candi, int begin, int target) {
if (!target) {
res.push_back(path);
return;
}
// 已排序的数组方便剪枝
for(int i=begin;i<candi.size()&&candi[i]<=target;++i) {
path.push_back(candi[i]);
calSum(candi, i, target-candi[i]);
path.pop_back();
}
}
vector<int> path;
vector<vector<int>> res;
};// Combination Sum II
// 题目描述:待选的数组是重复的,每个元素只能被选一次
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
calSum(candidates, 0, target);
return res;
}
void calSum(vector<int>& candi, int begin, int target) {
if (!target) {
res.push_back(path);
return;
}
for(int i=begin;i<candi.size()&&candi[i]<=target;++i) {
// 已排序好的数组方便去重
if (begin==i || candi[i] != candi[i-1]) {
path.push_back(candi[i]);
calSum(candi, i+1, target-candi[i]);
path.pop_back();
}
}
}
vector<int> path;
vector<vector<int>> res;
};// Combination Sum III
// 题目描述:只能从1到9中选择而且不允许重复选择
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<int> candi;
for(int i=1;i<=9;++i) candi.push_back(i);
calSum(candi, 0, n, k);
return res;
}
void calSum(vector<int>& candi, int begin, int target, int k) {
if (!target) {
if (k==0) res.push_back(path);
return;
}
if (!k) return;
for(int i=begin;i<candi.size()&&candi[i]<=target;++i) {
path.push_back(candi[i]);
calSum(candi, i+1, target-candi[i], k-1);
path.pop_back();
}
}
vector<int> path;
vector<vector<int>> res;
};#递归 #回溯法