这个题目很显然是一个回溯算法题,还是一个比较典型的题目。对于回溯法我们要明确两点:1.搜索的范围。2.剪枝的条件
这个剪枝的条件既包括终止回溯,也包括跳过某个搜索分支(也就是不能开分支的情况)
明确了以上两点回溯法基本大概的思路就可以成型了,剩下的也只是一些细节和边界情况的处理
回溯的一般模板是:
backtracking(回溯起点,结果容器,中间结果容器)
边界处理->一般都是超出搜索范围或者继续搜索下去绝对不可能再满足题目条件,也就是走远了
结果处理->就是已经满足条件了,应该终结当前分支了
搜索&&开分支
(可选,往往是处理结果重复的情况,比如有相等数字,这个时候就continue,进入下一次搜索)
将分支路径存入中间结果容器
backtracking(回溯起点[+1],结果容器,中间结果容器)//这个+1是可选的,一般来说当动作可以重复进行(比如数字可以重复选)的时候就不加1,如果不能重复,就加1
将分支路径移离中间结果容器(这个是回溯的一般特征,现场还原,就是对尝试性的动作进行“回溯”)
总结了模板之后再回到本题进行分析,本题题目要求我们组合数字进行求和(边界1),并且数字个数限定(边界2),数字不能重复选择(搜索剪枝条件1),数字范围是1-9(搜索范围)
以上我们就明确了回溯的两个重要条件,边界(剪枝条件)和搜索范围
我们还可以在开始回溯之前再做一个小优化,因为我们只能选1-9的数字,并且不能重复选,所以这个和最多不能超过90(1-9的累加和)
下面看代码:
class Solution {
public List<List> combinationSum3(int k, int n) {
List<List> res=new ArrayList();
Deque q=new ArrayDeque();
if(n>90) return res;
backtracking(k,0,n,1,res,q);
return res;
}
public void backtracking(int k,int d,int n,int num,List<List> res,Deque q)
{
if(n<0) return;
if(n0&&dk)
res.add(new ArrayList(q));
for(int i=num;i<10;++i)
{
q.addLast(i);
backtracking(k,d+1,n-i,i+1,res,q);
q.pollLast();
}
}
}
时间复杂度:O(N^2)
空间复杂度:O(lgN)