一、题目描述

找出所有相加之和为 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]]

二、解题思路

我们需要在 9 个数中选择 k 个数,让它们的和为 nn。

这样问题就变成了一个组合枚举问题。

这里我们要做的是做一个「在 9 个数中选择 k 个数」的组合枚举,对于枚举到的所有组合,判断这个组合内元素之和是否为 n。

三、代码

public class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
int[] a={1,2,3,4,5,6,7,8,9};
List<List<Integer>> rs=new ArrayList<List<Integer>>();
List<Integer> list=new ArrayList<Integer>();
dfs(a,list,rs,k,n,0);
return rs;
}
void dfs(int[] a,List<Integer> list,List<List<Integer>> rs,int k,int target,int index){
if(index==a.length){
if(target==0&&list.size()==k){
rs.add(new ArrayList<Integer>(list));
return;
}
return;
}
if(target==0&&list.size()==k){
rs.add(new ArrayList<Integer>(list));
return;
}
dfs(a,list,rs,k,target,index+1);//不选
if(target-a[index]>=0){//选择
list.add(a[index]);
dfs(a,list,rs,k,target-a[index],index+1);
list.remove(list.size()-1);
}
}

public static void main(String[] args) {
Solution solution=new Solution();
List<List<Integer>> rs=solution.combinationSum3(9,45);
for(List<Integer> list:rs){
for(Integer i:list){
System.out.print(i+",");
}
System.out.println();
}
}
}

四、复杂度分析

时间复杂度:O(S),其中 S 为所有可行解的长度之和。从分析给出的搜索树我们可以看出时间复杂度取决于搜索树所有叶子节点的深度之和,即所有可行解的长度之和。在这题中,我们很难给出一个比较紧的上界,我们知道 O(n×2^n) 是一个比较松的上界,即在这份代码中,n个位置每次考虑选或者不选,如果符合条件,就加入答案的时间代价。但是实际运行的时候,因为不可能所有的解都满足条件,递归的时候我们还会用 target - candidates[idx] >= 0 进行剪枝,所以实际运行情况是远远小于这个上界的。

空间复杂度:O(target)。除答案数组外,空间复杂度取决于递归的栈深度,在最差情况下需要递归 O(target) 层。