77.组合

下面我通过讲解一道回溯、递归类型的题目帮助大家快速的理解递归的用法
题目描述:

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。

题目示例:

输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

这道题什么意思呢,就是给你一个n,则会生成一个数组为[ 1,2,3,…,n],然后让你输出这个数组的全排列
这道题是一道很典型的回溯与剪枝类型的题目,我们通过下面这个方式 来理解:
我们以n=4,k=3为例,则会形成若干个下图所示的二叉树
在这里插入图片描述

我们可以看到我们能够形成的组合则有[ 1,2,3][ 1,2,4][ 1,3,4][ 2,3,4]所以说有效的则是层数为3的树
而我们接下来就是将这些树给构造出来

  • n 表示范围为 1…n,balance 表示剩余空间,start 表示开始位置,list 为回溯列表
  • 判断 balance == 0,如果为 0 则代表 list 中已经存入 k 个数,拷贝 list 存入结果 ans 中
  • 如果不为 0,从 start 位置开始递归调用,现将当前位置数据加入 list 中,并进入下一层,等待返回后将本层加入的数据移除,本质就是树的构造过程
  • 循环结束的条件就是我们从1-n全部遍历结束,但是我刚刚说过有效的树只有层数k的树,所以我们剪枝的临界点则为n-balance+1

代码如下:

package com.exercise.leetecode.递归And回溯;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class 组合_77 {

    static List<List<Integer>> ans = new ArrayList<>();

    public static List<List<Integer>> combine(int n, int k) {

        getCombine(n, k, 1, new ArrayList<>());//起始位置从1开始,1,2,...,n
        return ans;
    }

    public static void getCombine(int n, int k, int start, List<Integer> list) {
        if (k == 0) {//一旦剩余空间为0,则表示list中已经存放了k个数
            ans.add(new ArrayList<>(list));
            return;
        }
        for (int i = start; i <= n - k + 1; i++) {
            list.add(i);//开始填充当前位置的元素
            getCombine(n, k - 1, i + 1, list);//递归调用,即开始访问下一层
            //永远保留起始元素,删除后面不要的元素,执行改语句的条件只有两种:
            // 1.在k==0里的return执行完成之后才会执行该语句
            //2.每一次的for循环执行结束,比如:i由1通过i++变成2时表示第一次循环结束,则会在循环结束时执行该语句
            list.remove(list.size() - 1);
        }
    }


    public static void main(String[] args) {
        System.out.println(Arrays.toString(combine(4, 2).toArray()));

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZNineSun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值