第七章回溯_组合

吾日三省吾身

还记得的梦想吗

正在努力实现它吗

可以坚持下去吗


力扣题号: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~

相关推荐
劲夫学编程20 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪22 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
阿伟*rui1 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
浮生如梦_2 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师4 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法