1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public List<List<Integer>> combinationSum3(int k, int n) { List<List<Integer>> ans = new ArrayList<>(); helper(ans, new ArrayList<>(), 1, k, n); return ans; }
private void helper(List<List<Integer>> ans, List<Integer> curr, int pos, int k, int remain) { if (curr.size() == k) { if (remain == 0) { ans.add(new ArrayList<>(curr)); } return; } if (remain < 0) { return; } for (int i = pos; i < 10; i++) { curr.add(i); helper(ans, curr, i + 1, k, remain - i); curr.remove(curr.size() - 1); } } }
|
就是轮流找人当开头. 递归函数的功能就是给它一个pos(也就是选数只能从哪里开始往后选), 以及要凑的数remain, 它能给我们找到所有凑的方式. 那么我们用一个curr数组, 把我们当前的选择记录的curr里面, 然后之后交给递归函数去找并在curr中append它找到的组合. 大概就是这样.
时间复杂度: O(c9k) 也就是从9个中挑k个, 看有几种挑法. 但是我们适当的剪枝, 也就是当没凑个k个时但是remain小于0时, 直接return, 没必要再找了. 因此时间会快一些. 15行的优化很重要.
空间复杂度: O(n) 我们最多选9个数字, 因此递归函数的深度也是9.
每次就是选一个数字当开头, 然后继续在可以的范围内再选数字当开头.