第七章回溯_组合

吾日三省吾身

还记得的梦想吗

正在努力实现它吗

可以坚持下去吗


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

相关推荐
二哈赛车手3 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
吃好睡好便好3 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
栗子~~3 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
YDS8294 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
仰泳之鹅4 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
未若君雅裁5 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis
于小猿Sup5 小时前
VMware在Ubuntu22.04驱动Livox Mid360s
linux·c++·嵌入式硬件·自动驾驶
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题 第65题】【JVM篇】第25题:谈谈对 OOM 的认识
java·开发语言·jvm
阿维的博客日记6 小时前
Nacos 为什么能让配置动态生效?(涉及 @RefreshScope 注解)
java·spring
雨辰AI6 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务