第七章回溯_组合

吾日三省吾身

还记得的梦想吗

正在努力实现它吗

可以坚持下去吗


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

相关推荐
泡海椒6 小时前
JQuick-java (JQuick-ASM)性能优化原理:字节码生成与缓存机制深度解析
java·缓存·性能优化
光电笑映6 小时前
Linux 线程同步与互斥:锁的本质、条件变量与信号量的底层原理
linux·运维·服务器·开发语言·c++
Bs_MoneyMagnet6 小时前
基于springboot+vue的家居生活商城平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
微三云 - 廖会灵 (私域系统开发)6 小时前
Spring Boot实战:五级分销定价与自动分佣系统设计与实现
java·spring boot·后端
Json____6 小时前
从零构建在线拍卖系统:Java 全栈开发实践
java·开发语言·管理系统·it学习·wwwoop.com
jearry6 小时前
WebView2 原生拖放的桥接之道:拆解 yyzTools 的 drop-zone.js
前端·c++
我命由我123456 小时前
Android Compose 开发,使用 ConstraintLayout,但是引入的是旧的 ConstraintLayout
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
零基础的修炼6 小时前
CUDA知识汇总
开发语言·c++·编辑器
钱栈up6 小时前
mvn compile卡住半小时:定位并修复隐藏的类型不匹配编译错误
java·后端·maven
Zane19946 小时前
Lambda表达式没有类型,为什么还能被当成参数传来传去
java·后端