找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
题解(一):这道题的枚举总数最多不过是2^9个,我们可以直接遍历每一种组合情况,找出符合要求的组合。进行枚举时,我们可以使用二进制枚举法,利用二进制数字来帮助我们遍历所有的组合。对这道题而言,就是九位二进制数字,如果某位上的数字为1,则选择该位的位数数字,若为0则不选择该位的位数数字(例:000001101,则代表的数字组合[1,3,4])
class Solution {
private final List<Integer>tempList=new Vector<>();
private final List<List<Integer>>res=new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
//0~1 <<9中的每一个数字的二进制形式都代表了一种组合情况
for(int mask=0;mask<(1<<9);mask++){
if(checkSum(mask,n, k))
res.add(new ArrayList<>(tempList));
}
return res;
}
private boolean checkSum(int mask,int n,int k){
tempList.clear();
for(int i=0;(1<<i)<mask;i++){
//判断二进制数字第i+1位的数字是否为1
if(((1<<i)&mask)!=0)
tempList.add(i+1);
}
int sum=0;
for(int x:tempList)
sum+=x;
return sum==n&&tempList.size()==k;
}
}
题解(二):回溯法
(算法具体做法类比leetcode39(组合总和I)和leetcode40(组合总和II))
class Solution {
private final Stack<Integer>stack=new Stack<>();
private final List<List<Integer>>res=new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
backTrace(1,n,0,k,0);
return res;
}
private void backTrace(int min,int n,int sum,int k,int size){
if(n-sum<min||size>k)
return;
if(size==k-1){
if(n-sum>=min&&n-sum<=9&&n-sum>=0) {
stack.push(n - sum);
res.add(getArray(stack));
stack.pop();
}
return;
}
for(int i=min;i<=9;i++){
stack.push(i);
backTrace(i+1,n,sum+i,k,size+1);
stack.pop();
}
}
private List<Integer> getArray(Stack<Integer>stack){
return new ArrayList<>(stack);
}
}