找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

1.本题是一个经典的回溯算法题目,怎么辨别题解需要使用回溯算法呢?
回溯法,一般可以解决如下几种问题:
2.回溯法模板
回溯三部曲:
(1)返回值以及参数
返回值一般为void。再来看一下参数,因为回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数
(2)回溯函数终止条件
什么时候达到了终止条件,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归
(3)回溯搜索的遍历过程。
for循环是横向遍历可以理解一个节点有多少个孩子,这个for循环就执行多少次
backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
总结回溯算法模板如下:
- void backtracking(参数) {
- if (终止条件) {
- 存放结果;
- return;
- }
-
- for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
- 处理节点;
- backtracking(路径,选择列表); // 递归
- 回溯,撤销处理结果
- }
- }
3.代码
和77.组合http://t.csdn.cn/VUS9I一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。
这里我依然定义path 和 result为全局变量。
接下来还需要如下参数:
代码为:
- class Solution {
- List<List<Integer>> result = new ArrayList<>();
- LinkedList<Integer> path = new LinkedList<>();
- public List<List<Integer>> combinationSum3(int k, int n) {
- backTracking(n, k, 1, 0);
- return result;
- }
-
- private void backTracking(int targetSum, int k, int startIndex, int sum) {
- // 减枝
- if (sum > targetSum) {
- return;
- }
- if (path.size() == k) {
- if (sum == targetSum) result.add(new ArrayList<>(path));
- return;
- }
- // 减枝 9 - (k - path.size()) + 1
- for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
- path.add(i);
- sum += i;
- backTracking(targetSum, k, i + 1, sum);
- //回溯
- path.removeLast();
- //回溯
- sum -= i;
- }
- }
- }