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();
        }
    }
}

思路来源:代码随想录

相关推荐
小冯记录编程18 分钟前
深入解析C++ for循环原理
开发语言·c++·算法
chenchihwen2 小时前
深度解析RAG系统中的PDF解析模块:Docling集成与并行处理实践
python·算法·pdf
做科研的周师兄3 小时前
【机器学习入门】7.4 随机森林:一文吃透随机森林——从原理到核心特点
人工智能·学习·算法·随机森林·机器学习·支持向量机·数据挖掘
Sunsets_Red3 小时前
差分操作正确性证明
java·c语言·c++·python·算法·c#
【杨(_> <_)】4 小时前
SAR信号处理重要工具-傅里叶变换(二)
算法·信号处理·傅里叶分析·菲涅尔函数
怎么没有名字注册了啊4 小时前
爬动的蠕虫
算法
取酒鱼食--【余九】4 小时前
机器人学基础(一)【坐标系和位姿变换】
笔记·算法·机器人·开源·机器人运动学·机器人学基础
晨非辰4 小时前
【面试高频数据结构(四)】--《从单链到双链的进阶,读懂“双向奔赴”的算法之美与效率权衡》
java·数据结构·c++·人工智能·算法·机器学习·面试
im_AMBER4 小时前
数据结构 03 栈和队列
数据结构·学习·算法
凸头4 小时前
以AtomicInteger为例的Atomic 类的底层CAS细节理解
java·jvm·算法