LeetCode216
目录
- 题目描述
- 示例
- 思路分析
- 代码段
- 代码逐行讲解
- 复杂度分析
- 总结的知识点
- 整合
- 总结
题目描述
找出所有相加之和为 target
的 k
个数的组合,且满足以下条件:
- 只使用数字 1 到 9。
- 每个数字最多使用一次。
返回所有可能的有效组合的列表。组合中不能有相同的组合,组合可以以任何顺序返回。
示例
示例 1
输入:
k = 3, target = 7
输出:
[[1, 2, 4]
]
解释:
- 1 + 2 + 4 = 7。
- 没有其他符合条件的组合。
示例 2
输入:
k = 3, target = 9
输出:
[[1, 2, 6],[1, 3, 5],[2, 3, 4]
]
解释:
- 1 + 2 + 6 = 9。
- 1 + 3 + 5 = 9。
- 2 + 3 + 4 = 9。
思路分析
问题核心
我们需要找到所有由 k
个不同数字组成的组合,且这些数字的和为 target
。数字的范围是 1 到 9,且每个数字只能使用一次。
思路拆解
- 深度优先搜索(DFS):
- 使用 DFS 遍历所有可能的组合。
- 剪枝:
- 如果当前数字大于剩余的目标值
target
,则跳过该数字。
- 如果当前数字大于剩余的目标值
- 回溯:
- 在 DFS 过程中,使用
stack
记录当前组合,并在回溯时移除最后一个数字。
- 在 DFS 过程中,使用
- 终止条件:
- 如果当前组合的长度等于
k
且和为target
,则将其加入结果列表。
- 如果当前组合的长度等于
代码段
class Solution {public List<List<Integer>> combinationSum3(int k, int target) {List<List<Integer>> result = new ArrayList<>(); dfs(1, target, k, new LinkedList<>(), result); return result;}private static void dfs(int start, int target, int k,LinkedList<Integer> stack,List<List<Integer>> result) {if (target == 0 && stack.size() == k) { result.add(new ArrayList<>(stack));return;}for (int i = start; i <= 9; i++) {if (target < i) { continue;}stack.push(i); dfs(i + 1, target - i, k, stack, result); stack.pop();}}
}
代码逐行讲解
1. 初始化结果列表
List<List<Integer>> result = new ArrayList<>();
result
用于存储所有符合条件的组合。
2. 调用 DFS
dfs(1, target, k, new LinkedList<>(), result);
- 调用 DFS 函数,传入起始数字
1
、目标值target
、组合长度k
、stack
(用于记录当前组合)和结果列表result
。
3. DFS 函数
private static void dfs(int start, int target, int k,LinkedList<Integer> stack,List<List<Integer>> result) {
- DFS 函数的定义,用于递归生成组合。
4. 找到一个组合
if (target == 0 && stack.size() == k) {result.add(new ArrayList<>(stack));return;
}
- 如果当前组合的长度等于
k
且和为target
,则将其加入结果列表。
5. 遍历数字 1 到 9
for (int i = start; i <= 9; i++) {
- 从
start
开始遍历数字 1 到 9,尝试将其加入当前组合。
6. 剪枝
if (target < i) {continue;
}
- 如果当前数字大于剩余的目标值
target
,则跳过该数字。
7. 加入当前数字
stack.push(i);
- 将当前数字加入当前组合。
8. 递归
dfs(i + 1, target - i, k, stack, result);
- 递归调用 DFS,继续生成下一个数字的组合。
9. 回溯
stack.pop();
- 回溯时移除当前数字,尝试其他可能的组合。
复杂度分析
时间复杂度
- 组合的数量为
C(9, k)
,即从 9 个数字中选k
个数字的组合数。 - 每次生成一个组合需要
O(k)
的时间。 - 因此,总时间复杂度为 O(C(9, k) * k)。
空间复杂度
- 需要存储所有组合,空间复杂度为 O(C(9, k) * k)。
- 递归栈的深度为
k
,因此额外空间复杂度为 O(k)。
总结的知识点
1. 深度优先搜索(DFS)
- 使用 DFS 遍历所有可能的组合。
2. 剪枝
- 在 DFS 过程中,通过条件判断跳过无效的搜索路径。
3. 回溯
- 在 DFS 过程中,使用
stack
记录当前组合,并在回溯时移除最后一个数字。
4. 组合问题
- 通过限制搜索的起始位置(
start
参数),避免生成重复的组合。
整合
class Solution {public List<List<Integer>> combinationSum3(int k, int target) {List<List<Integer>> result = new ArrayList<>(); // 结果列表dfs(1, target, k, new LinkedList<>(), result); // DFSreturn result;}private static void dfs(int start, int target, int k,LinkedList<Integer> stack,List<List<Integer>> result) {if (target == 0 && stack.size() == k) { // 找到一个组合result.add(new ArrayList<>(stack));return;}// 遍历数字 1 到 9for (int i = start; i <= 9; i++) {if (target < i) { // 剪枝continue;}stack.push(i); // 加入当前组合dfs(i + 1, target - i, k, stack, result); // 递归stack.pop(); // 回溯}}
}
总结
通过 DFS 和回溯,高效地找到所有由 k
个不同数字组成的组合,且这些数字的和为 target
。