回溯算法01-组合(Java)

文章讲述了如何利用回溯算法解决给定整数n和k的组合问题,通过递归方式生成所有可能的k个数的组合,避免了直接枚举的复杂性,以Java代码为例详细阐述了算法实现过程。
摘要由CSDN通过智能技术生成

1.组合

  • 题目描述

给定两个整数 nk,返回范围 [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这n个不同的数的组合问题,我们知道对于n个不同的数中的任意k个数组合,当n很大时通过枚举是很难将它枚举完成的,所以我们可以采用回溯算法来解决这一类问题。
  • 回溯算法的模板

1.确立递归函数及返回值

2.确立回溯的终止条件

3.单层递归逻辑

private void backtracking(参数) {
	//回溯的终止条件
    if (终止条件) {
        存放结果;
        return;
    }
	//回溯算法的遍历过程(集合的大小为树的宽度,递归的深度为树的深度)
    for (选择 :本层集合的元素) {
        处理节点;
        backtracking(路径, 选择列表);//递归
        回溯,撤销处理的结果
    }
}
1.首先我们确立递归函数及参数(例子:nums=[1,2,3] k = 2)
根据下图递归操作我们可以看出,每次挑选数组nums中的一个元素加入到集合之中:
第一次:集合元素为[1],剩余元素为[2,3]
第二次:集合元素为[1,2],剩余元素为[3] 此时集合[1,2]满足k = 2的组合条件,将其存储,因为之后不再再取3会使不满足k个数组合的条件,因此要进行回溯,返回到集合元素为[1],剩余元素为[2,3]
第三次:集合元素为[1,3],剩余元素为[] 此时要选择元素3加入到集合,因此我们要设置一个索引来避开元素2,这样才不会有重复
...依次回溯,我们发现每次叶子节点为我们想要的结果
 
所以初始化一个回溯函数
void backtrack(int nums[], int startIndex) {
    
}
nums为要组合的元素集合,startIndex为避免每次重复的指针

2.设置终止条件:当我们组合的集合中恰好有k个节点时,表示组合完成
    
3.单层递归逻辑
从startIndex开始,遍历所有可能的元素,将其添加到路径中,并递归调用backtrace方法继续生成下一个元素。完成递归后,需要将最后一个元素从路径中移除,以便尝试其他可能的元素。

image-20240305194217384

  • 以nums=[1,2,3,4] k = 2直观感受一下i与startIndex的变化
i = 1 s = 1 [1]
i = 2 s = 2 [1,2]
//i = 2 s = 2 [1]
i = 3 s = 2 [1,3]
//i = 3 s = 2 [1] 
i = 4 s = 2 [1,4]
//i = 4 s = 2 [1]
i = 2 s = 1 [2]
i = 3 s = 3 [2,3]
//i = 3 s = 3 [2]
i = 4 s = 3 [2,4]
//i = 4 s = 3 [2]
i = 3 s = 1 [3]
...
  • Java代码实现
//list:用于存储一条路径上的元素
    //result:用于返回最后的元素
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtrace(n, k, 1);
        return result;
    }

    //1.确立递归函数的参数及返回值
    //n:树的宽度即求n个数的组合数
    //k:叶子节点即组合个数为k
    //startIndex:用于开始元素遍历的起点
    private void backtrace(int n, int k, int startIndex) {
        //2.确立终止条件
        if (path.size() == k) {//当最后组成的元素集合为k时返回结果
            result.add(new LinkedList<>(path));
            return;
        }
        //3.单层递归逻辑
        for (int i = startIndex; i <= n; i++) {
            path.add(i);
            backtrace(n, k, i + 1);
            path.removeLast();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值