Combination Sum Series
Combination Sum Series
I worked through all the Combination Sum problems in one go. This gave me a deeper understanding of backtracking and exhaustive search. Here’s what I learned.
Core Idea
Choose recursively, then backtrack that choice. This pattern works well for combinatorial search problems.
void Sum(int begin, vector<T> path, vector<T> candi, ...) {
if(meets end condition) return;
// Search all elements in range
for(i=begin...N) {
// Choose this element
path.push_back(candi[i]);
// Call Sum(..) to keep searching
path.pop_back(); // backtrack
}
}The rest is just template code.
// Combination Sum
// The candidate array has no duplicates, but we can reuse elements
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;
}
// Sorted arrays help with pruning
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
// The candidate array has duplicates, each element used once
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) {
// Sorted arrays help remove duplicates
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
// Choose from 1 to 9 only, no repeated selections
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;
};#recursion #backtracking