给定两个整数 n
和 k
,返回范围 [1, n]
中所有可能的 k
个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
示例 2:
输入:n = 1, k = 1 输出:[[1]]
提示:
1 <= n <= 20
1 <= k <= n
要解决这个问题,我们可以使用回溯算法。回溯算法是一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化丢弃该解,即回溯并且再次尝试。
为了生成所有可能的组合,我们可以从数字1开始,依次尝试每一个数字,对于每一个数字,我们都可以选择将其放入当前的组合中,或者不放入。如果放入,我们就继续向组合中添加下一个数字;如果不放入,我们就尝试下一个数字。当我们组合中的数字数量达到k时,我们就找到了一个有效的组合,将其添加到结果列表中。
具体步骤如下:
1. 初始化一个结果列表result
,用于存储所有有效的组合。
2. 定义一个回溯函数backtrack
,该函数接受以下参数:
result
:结果列表comb
:当前组合start
:当前尝试的数字n
:数字范围上限k
:组合大小3. 在backtrack
函数中,首先检查当前组合的大小是否等于k:
4. 从start
开始,遍历所有可能的数字:
backtrack
函数,尝试下一个数字,即start + 1
。5. 在combine
函数中,首先检查k是否小于等于0或n是否小于k:
backtrack
函数。这样,我们就可以生成所有的组合,并将它们存储在结果列表中。最后,返回结果列表即可。
- import java.util.ArrayList;
- import java.util.List;
-
- public class Solution {
- public List
> combine(int n, int k) {
- List
> result = new ArrayList<>();
- if (k <= 0 || n < k) {
- return result;
- }
- // 从1开始进行回溯
- backtrack(result, new ArrayList<>(), 1, n, k);
- return result;
- }
-
- private void backtrack(List
> result, List comb, int start, int n, int k)
{ - if (comb.size() == k) {
- // 找到一个有效的组合
- result.add(new ArrayList<>(comb));
- return;
- }
-
- for (int i = start; i <= n; i++) {
- // 添加当前数字到组合中
- comb.add(i);
- // 递归地继续向组合中添加数字
- backtrack(result, comb, i + 1, n, k);
- // 回溯:移除最后一个数字,尝试下一个数字
- comb.remove(comb.size() - 1);
- }
- }
- }
回溯算法:这是一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化丢弃该解,即回溯并且再次尝试。
递归:backtrack
函数是一个递归函数,它通过自己调用自己来进行深度优先搜索(DFS)。递归允许函数在执行过程中调用自己,从而可以遍历所有可能的组合。
列表(ArrayList):result
和 comb
都是 ArrayList
类型的列表,用于存储组合结果和当前的组合。ArrayList
是 Java 中的一个可调整大小的数组实现,提供了对元素的快速随机访问。
条件语句:代码中使用了条件语句(if
)来检查组合的大小是否达到了k,以及输入参数是否有效。
循环语句:for
循环用于遍历所有可能的数字,从 start
到 n
。
列表操作:add
和 remove
方法用于在组合列表中添加和移除元素。这是对列表进行动态操作的基本方法。
函数定义和调用:代码中定义了 combine
和 backtrack
两个函数,combine
是公共函数,用于对外提供接口,而 backtrack
是一个私有辅助函数,用于实现回溯逻辑。
参数传递:函数通过值传递(int n, int k
)和引用传递(List
)来传递参数。在 Java 中,基本数据类型(如 > result, List
int
)是通过值传递的,而对象(如 List
)是通过引用传递的。
深拷贝和浅拷贝:在将 comb
添加到 result
时,使用了 new ArrayList<>(comb)
来创建 comb
的深拷贝。这是因为 ArrayList
是可变的,如果不进行深拷贝,result
中存储的将是 comb
引用的副本,而不是其值的副本。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。