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

思路来源:代码随想录

相关推荐
ん贤20 分钟前
贪心算法.
算法·贪心算法
cndes28 分钟前
大数据算法的思维
大数据·算法·支持向量机
Mopes__2 小时前
Python | Leetcode Python题解之第461题汉明距离
python·leetcode·题解
睡不着还睡不醒2 小时前
【数据结构强化】应用题打卡
算法
sp_fyf_20242 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-05
人工智能·深度学习·神经网络·算法·机器学习·语言模型·自然语言处理
Mopes__3 小时前
Python | Leetcode Python题解之第452题用最少数量的箭引爆气球
python·leetcode·题解
C++忠实粉丝3 小时前
前缀和(6)_和可被k整除的子数组_蓝桥杯
算法
木向3 小时前
leetcode42:接雨水
开发语言·c++·算法·leetcode
TU^3 小时前
C语言习题~day16
c语言·前端·算法