void backtrack(参数列表) {
if (终止条件) {
收集结果;
return;
}
for (选择范围内的选项) {
做出选择;
backtrack(新参数); // 递归
撤销选择; // 回溯,恢复状态
}
}
LeetCode 77题(组合)要求从1到n中选择k个数字的所有可能组合,且组合中的元素不能重复,顺序不影响组合的唯一性(例如[1,2]和[2,1]视为同一个组合)。
这是一个典型的组合问题,适合用回溯算法解决。
解题思路解析
-
回溯算法框架:
- 选择:从1到n中选择一个数字
- 约束:每个数字只能选一次,且组合中数字递增(避免重复)
- 目标:选出k个数字
-
关键优化:
- 通过
start参数控制每次选择的起始位置,确保组合中的数字递增,避免产生重复组合 - 剪枝操作:计算i的上限为
n - (k - path.size()) + 1,减少不必要的循环
- 通过
-
时间复杂度:
- 生成了C(n,k)个组合,每个组合需要O(k)的时间复制到结果中
- 总体时间复杂度为O(C(n,k) × k)
import java.util.ArrayList;
import java.util.List;
public class Combinations {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> result = new ArrayList<>();
// 处理边界情况
if (n < k || k <= 0) {
return result;
}
// 调用回溯函数
backtrack(n, k, 1, new ArrayList<>(), result);
return result;
}
/**
* 回溯函数
* @param n 范围上限
* @param k 需要选择的数字个数
* @param start 起始数字(用于避免重复组合)
* @param path 当前路径(已选择的数字)
* @param result 结果集合
*/
private void backtrack(int n, int k, int start, List<Integer> path, List<List<Integer>> result) {
// 终止条件:已选择k个数字
if (path.size() == k) {
result.add(new ArrayList<>(path));
return;
}
// 遍历可能的选择
// 剪枝优化:i的上限可以计算为n - (k - path.size()) + 1
for (int i = start; i <= n - (k - path.size()) + 1; i++) {
// 做出选择
path.add(i);
// 递归:下一次选择从i+1开始,避免重复
backtrack(n, k, i + 1, path, result);
// 撤销选择(回溯)
path.remove(path.size() - 1);
}
}
public static void main(String[] args) {
Combinations solution = new Combinations();
// 测试用例
System.out.println(solution.combine(4, 2));
// 输出: [[1,2], [1,3], [1,4], [2,3], [2,4], [3,4]]
System.out.println(solution.combine(1, 1));
// 输出: [[1]]
}
}
533

被折叠的 条评论
为什么被折叠?



