216. Combination Sum III
Medium
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Note:
All numbers will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:
Input: k = 3, n = 7
Output: [[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output: [[1,2,6], [1,3,5], [2,3,4]]
题意
给定正整数k和正整数n,求所有的k个不同的1~9之间的正整数的组合,使得这k个数的和为n
思路
dfs, dfs递归方法的参数有4个,分别是:
num: k个正整数还剩下num个未确定
cur: 当前搜索到1~9中的哪一个数
target: 原来的n经过之前的搜索之后还剩target没有满足
list: 记录已经搜索的数字
最后是一点评论。大家一定都做过硬币找零问题,例如硬币找零–动态规划入门,硬币找零问题是一个经典的动态规划问题。大家也一定都知道,一般来说,一个问题如果既可以用动态规划求解又可以用深搜求解,用动态规划是更快的,因为动态规划可以保存中间计算的状态,避免子问题的重复计算。
那么问题是,为什么LeetCode上Combination Sum系列的题目要用深搜来解而经典的硬币找零问题可以用动态规划求解?原因在于Combination Sum要求数组中每个数只能使用一次,因此一个深搜里的一个状态(或者说是动态规划里的一个子问题),不仅包含num和target,还包含数组中的数是否使用的一个bitmap. 对于动态规划来说,这会造成子问题规模的爆炸。
代码
class Solution {
private List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> combinationSum3(int k, int n) {
if (n <= 0 || n > 45) {
return ans;
}
dfs(k, 9, n, new LinkedList<Integer>());
return ans;
}
private void dfs(int num, int cur, int target, LinkedList<Integer> list) {
if (num == 0) {
if (target == 0) {
ans.add(new LinkedList(list));
}
return;
}
if (cur == 0) {
return;
}
if (cur <= target) {
list.add(cur);
dfs(num-1, cur-1, target-cur, list);
list.removeLast();
}
dfs(num, cur-1, target, list);
}
}