Leetcode77:组合问题
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()) + 1for (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]]}
}