找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
所有数字都是正整数。
解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解题思路:回溯+剪枝
方法一:单纯的回溯,纯暴力,代码和提交结果如下:
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
ArrayList<List<Integer>> res = new ArrayList<>();
Stack<Integer> paths = new Stack<>();
dfs(res,paths,0,n,k,1);
return res;
}
private static void dfs(List<List<Integer>> res, Stack<Integer> paths , int sum ,int n, int k ,int begin){
if(sum == n && paths.size() == k){
res.add(new ArrayList<>(paths));
return;
}
if(sum > n || paths.size() > k){
return;
}
for (int i = begin; i <= 9; i++) {
paths.push(i);
sum+=i;
dfs(res,paths,sum,n,k,i+1);
sum-=i;
paths.pop();
}
}
}
方法二:回溯加剪枝
两种剪枝情况:
情况一:在计算的过程当中,如果组合总数已经不够k,便可以直接剪枝,(纵向剪枝)
情况二:因为是1-9,所以当组合的sum 已经大于要等于的n时,所有横向剩余的 i 都需要剪枝(横向剪枝)
代码如下:
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
ArrayList<List<Integer>> res = new ArrayList<>();
Stack<Integer> paths = new Stack<>();
dfs(res,paths,0,n,k,1);
return res;
}
private static void dfs(List<List<Integer>> res, Stack<Integer> paths , int sum ,int n, int k ,int begin){
if(paths.size() == k){
if(sum == n){
res.add(new ArrayList<>(paths));
}
return;
}
if(sum > n){
return;
}
for (int i = begin; i <= 10-(k-paths.size()) && sum + i <= n; i++) {
paths.push(i);
sum+=i;
dfs(res,paths,sum,n,k,i+1);
sum-=i;
paths.pop();
}
}
}
总结: 注意横向剪枝和纵向剪枝