leetcode hot100组合

在本题中,是要求返回[1,n]这个数组的长度为k的组合。涉及到排列、组合、棋盘、分割等问题的时候,要考虑利用回溯来进行解决。

回溯和递归类似,也分为三步进行分析

  1. 确定递归函数的返回值和参数:一般来说返回值都是void,参数就需要根据题目来判断了。
  2. 确定递归的终止条件
  3. 确定单层处理的逻辑

那么一般的回溯题目都是可以套用模板的

复制代码
void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

以本题为例,返回值为void,参数我们需要存放整体结果的一个二维数组,还需要一个存放单层结果的一维链表。还有n和k,还需要一个startIndex

然后我们确定截至条件,也就是我们单层处理的时候,链表的长度为k,那么就直接把这个一维链表放入到二维数组中。然后return

最后我们在单层处理的时候,也就是for循环,从startIndex开始进行循环遍历,将结果存入一维链表,然后进行递归调用,最后我们还需要回溯撤销,将存入的下一个元素删除,比如一开始我们得到1,2。我们需要把2删除,然后再加入3变成1,3.

复制代码
class Solution {
    List<List<Integer>> result= new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtracking(n,k,1);
        return result;
    }

    public void backtracking(int n,int k,int startIndex){
        if (path.size() == k){
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i =startIndex;i<=n;i++){
            path.add(i);
            backtracking(n,k,i+1);
            path.removeLast();\\removelast可以删除链表最后一个元素并返回该元素
        }
    }
}

注意:removelast可以删除链表最后一个元素并返回该元素

result.add(new ArrayList<>(path)),之所以new ArrayList<>(path),是因为如果用result.add(path)会导致在向path中添加元素的时候,result发生变化。

res.add(new ArrayList(path)):开辟一个独立地址,地址中存放的内容为path链表,后续path的变化不会影响到res。

res.add(path):将res尾部指向了path地址,后续path内容的变化会导致res的变化

但是这里的代码是可以优化的,进行剪枝操作,来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。比如

那么,我们只需要改变for循环的截至条件就可以了。比如n = 4,k = 3,那么目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。

从2开始搜索都是合理的,可以是组合[2, 3, 4]。从3开始的话就不能再有3个数字的组合了。

所以,截至条件是for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置

复制代码
class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        combineHelper(n, k, 1);
        return result;
    }

    /**
     * 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex
     * @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。
     */
    private void combineHelper(int n, int k, int startIndex){
        //终止条件
        if (path.size() == k){
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){
            path.add(i);
            combineHelper(n, k, i + 1);
            path.removeLast();
        }
    }
}

思路来源:代码随想录

相关推荐
不穿格子的程序员8 小时前
从零开始写算法——链表篇:相交链表 + 反转链表
数据结构·算法·链表
仰泳的熊猫8 小时前
1132 Cut Integer
数据结构·c++·算法·pat考试
aini_lovee8 小时前
基于边缘图像分割算法详解与MATLAB实现
开发语言·算法·matlab
拼好饭和她皆失8 小时前
高效算法的秘诀:滑动窗口(尺取法)全解析
数据结构·算法·滑动窗口·尺取法
断剑zou天涯8 小时前
【算法笔记】二叉树的Morris遍历
数据结构·笔记·算法
元亓亓亓8 小时前
LeetCode热题100--739. 每日温度--中等
python·算法·leetcode
小白程序员成长日记8 小时前
2025.12.11 力扣每日一题
数据结构·算法·leetcode
一碗白开水一8 小时前
【论文阅读】Denoising Diffusion Probabilistic Models (DDPM)详细解析及公式推导
论文阅读·人工智能·深度学习·算法·机器学习
代码游侠8 小时前
学习笔记——进程
linux·运维·笔记·学习·算法
天赐学c语言8 小时前
12.11 - 最长回文子串 && main函数是如何开始的
c++·算法·leetcode