第七章回溯_组合

吾日三省吾身

还记得的梦想吗

正在努力实现它吗

可以坚持下去吗


力扣题号:77. 组合 - 力扣(LeetCode)

下述题目描述和示例均来自力扣

题目描述

给定两个整数 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 <= 20
  • 1 <= k <= n

思路

Java解法一:回溯算法

我们利用递归,在递归之中回溯,挨个的寻找我们所需要的目标。找到一个之后就删除最后那一个,这就是一个回溯的操作,然后再找。具体代码如下:

java 复制代码
class Solution {
    // 先创建两个全局变量
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();

    public List<List<Integer>> combine(int n, int k) {
        // 进入递归搜索
        backtracking(n, k, 1);
        // 此时已经递归回溯完毕,结果已经保存到了res中直接返回即可
        return res;
    }

    public void backtracking(int n, int k, int startIndex) {
        // 递归结束条件就是当前的元素集已经达到了k个
        if (path.size() == k){
            // 由于我们的path是linkedlist类型,所以要保存到res中要先转换乘Arraylist
            res.add(new ArrayList<>(path));
            // 终止
            return;
        }
        // 进入寻找过程
        for (int i = startIndex; i <= n ; i++) {
            path.add(i);
            backtracking(n, k, i + 1);
            // 删除最后一个元素,回溯
            path.removeLast();
        }
    }
}

拿下~!!!!


Java解法一:回溯算法剪枝操作

在回溯算法的开篇就提到了,回溯是一个暴力的枚举过程,唯一的优化方式也就是进行剪枝操作,非常幸运的是这道题就可以进行一个剪枝的操作。

思考一些问题。如果起始位置之后的元素个数已经小于我们需要的元素的个数,我们还需要在这个分支上浪费时间吗?答案显然是不需要了。

大概的优化思路如下(参考于《代码随想录》):

(1)已经选择的元素个数:path.size()

(2)还需要元素的个数: k - path.size()

(3)最多从起始位置 (n - ( k - path.size() )+ 1 ) 开始遍历

因此我们也只需要改变一下for循环的结束条件这么一处代码即可

java 复制代码
class Solution {
    // 先创建两个全局变量
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();

    public List<List<Integer>> combine(int n, int k) {
        // 进入递归搜索
        backtracking(n, k, 1);
        // 此时已经递归回溯完毕,结果已经保存到了res中直接返回即可
        return res;
    }

    public void backtracking(int n, int k, int startIndex) {
        // 递归结束条件就是当前的元素集已经达到了k个
        if (path.size() == k){
            // 由于我们的path是linkedlist类型,所以要保存到res中要先转换乘Arraylist
            res.add(new ArrayList<>(path));
            // 终止
            return;
        }
        // 进入寻找过程
        // 进行剪枝操作
        for (int i = startIndex; i <= (n - (k - path.size()) + 1) ; i++) {
            path.add(i);
            backtracking(n, k, i + 1);
            // 删除最后一个元素,回溯
            path.removeLast();
        }
    }
}

总结

组合问题是回溯算法的典型题目。可以通过剪枝的方法来优化我们的回溯代码~~

ヾ( ̄▽ ̄)Bye~Bye~

相关推荐
jingfeng5144 分钟前
C++ STL-string类底层实现
前端·c++·算法
郝学胜-神的一滴10 分钟前
基于C++的词法分析器:使用正则表达式的实现
开发语言·c++·程序人生·正则表达式·stl
还是鼠鼠28 分钟前
tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
java·spring boot·后端·spring·maven
雲墨款哥1 小时前
JS算法练习-Day10-判断单调数列
前端·javascript·算法
FPGA1 小时前
CRC校验原理及其FPGA实现
算法
Xiaokai丶1 小时前
Java 8 新特性深度剖析:核心要点与代码实战
java
灵魂猎手1 小时前
3. MyBatis Executor:SQL 执行的核心引擎
java·后端·源码
Galaxy在掘金1 小时前
从业8年,谈谈我认知的后端架构之路-1
java·架构
Jina AI1 小时前
回归C++: 在GGUF上构建高效的向量模型
人工智能·算法·机器学习·数据挖掘·回归
Coovally AI模型快速验证1 小时前
YOLO、DarkNet和深度学习如何让自动驾驶看得清?
深度学习·算法·yolo·cnn·自动驾驶·transformer·无人机