Tips:
这类题的共同点都是用backtracking,建立一个helper API然后recursion
- input candidates needs sort,一是为了方便判断sum target提前退出(减枝),二是为了方便remove duplicates
sort(candidates.begin(), candidates.end())
helper API有几个共同点:
- input:res,row,start
- exit condition:
1,如果return有array size要求,比如combinations,要求k=2,exit condition就是:row.size()==k
2,如果return是target,比如combinations sum I and II, 要求target,exit condition就是:
target == 0
并且可以提前return,
if(candidates[i] > target) return;
比如all combination sum。
3,如果return既有target,又有size要求,比如combination sum III,exit condition就是:
row.size()==k && target == 0 - start 在recursion时的选择
如果元素不能重复利用,recursion helper时start就是i + 1. (combination,combination sum II,combination sum III)
反之就是i (combination sum I) - 如果input candidates有重复元素,需要remove duplicates,
while(i+1 < candidates.size() && candidates[i] == candidates[i+1]) i++;
比如combination II。
Leetcode:
77. Combinations
Input: n = 4, k = 2
Output:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>>res;
if(n < k) return res;
vector<int>row;
combineHelper(res, row, n, k, 1);
return res;
}
private:
void combineHelper(vector<vector<int>> & res, vector<int>&row, int n, int k, int start)
{
if(row.size() == k)
{
res.push_back(row);
return;
}
for(int i = start; i <= n; i++)
{
row.push_back(i);
combineHelper(res, row, n, k, i+1);
row.pop_back();
}
}
};
};
- Combination Sum
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int>>res;
vector<int>row;
helper(res, row, candidates, target, 0);
return res;
}
void helper(vector<vector<int>> &res, vector<int>& row, vector<int>& candidates, int target, int start)
{
if(target == 0)
{
res.push_back(row);
return;
}
for(int i = start; i < candidates.size(); i++)
{
if(candidates[i] > target) return;
row.push_back(candidates[i]);
helper(res, row, candidates, target - candidates[i], i);
row.pop_back();
}
}
};
- Combination Sum II
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates may only be used once in the combination.
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>>res;
sort(candidates.begin(), candidates.end());
vector<int>row;
helper(candidates, res, row, target, 0);
return res;
}
void helper(vector<int>& candidates, vector<vector<int>>&res, vector<int>row, int target, int start)
{
if(target == 0)
{
res.push_back(row);
return;
}
for(int i = start; i < candidates.size(); i++)
{
if(candidates[i] > target)
{
return;
}
row.push_back(candidates[i]);
helper(candidates, res, row, target - candidates[i], i + 1);
row.pop_back();
while(i+1 < candidates.size() && candidates[i] == candidates[i+1]) i++;
}
}
};
- Combination Sum III
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>>res;
vector<int>row;
helper(res, row, k, n, 1);
return res;
}
void helper(vector<vector<int>>&res, vector<int>&row, int k, int target, int start)
{
if(row.size() == k && target == 0)
{
res.push_back(row);
return;
}
for(int i = start; i <= 9; i++)
{
if(i > target) return;
row.push_back(i);
helper(res, row, k, target - i, i + 1);
row.pop_back();
}
}
};