leecode77——组合(回溯算法)

news2025/5/23 9:46:09

leecode77 组合问题

在这里插入图片描述

🔎1.回溯算法是什么?

其实回溯算法和我们常说的 DFS 算法非常类似,本质上就是一种暴力穷举算法。回溯算法和 DFS 算法的细微差别是:回溯算法是在遍历「树枝」,DFS 算法是在遍历「节点」。

解决回溯问题,其实就是在遍历一棵决策树,站在回溯树的节点上,只需考虑以下三个问题:

🔵路径:也就是已经做出的选择
🔵选择列表:即就是当前可以做的选择
🔵结束条件:也就是到达决策树底层,无法再做选择

🔎2.回溯算法解决的问题:

回溯法,一般可以解决如下几种问题:

🔵组合问题:N个数里面按一定规则找出k个数的集合
🔵切割问题:一个字符串按一定规则有几种切割方式
🔵子集问题:一个N个数的集合里有多少符合条件的子集
🔵排列问题:N个数按一定规则全排列,有几种排列方式
🔵棋盘问题:N皇后,解数独等等

🔎3.回溯算法步骤

回溯算法中函数的返回值一般为void
(1)回溯函数终止条件
既然是树形结构,一般来说搜索到叶子节点,也就找到了一条满足条件的答案
回溯终止条件的伪代码如下:

if (终止条件) {
    存放结果;
    return;
}

(2)回溯的遍历过程在这里插入图片描述回溯函数遍历过程伪代码如下:

for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
    处理节点;
    backtracking(路径,选择列表); // 递归
    回溯,撤销处理结果
}

可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。

🔎4.回溯算法的模板代码框架

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

🔎代码如下:

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

举例:

假设给定 n = 4,k = 2,即从 [1, 2, 3, 4] 这个集合中选取 2 个元素进行组合。

1.首先,我们初始化 result 和 path:

List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();

2.开始调用 combine 方法:

combine(4, 2);

进入 combineHelper 方法,初始状态下 startIndex 为 1。

第一次递归调用:

combineHelper(4, 2, 1);

因为 path 的大小还不等于 2,我们进入循环 for (int i = startIndex; i <= n - (k - path.size()) + 1; i++),在此例中为 for (int i = 1; i <= 3; i++)。

第一次迭代,i = 1,我们将 1 添加到 path 中:

path.add(1); // path = [1]

然后进行递归调用:

combineHelper(4, 2, 2);

进入递归后,再次判断 path 的大小是否等于 2。此时还不满足,继续进行循环。由于 i 的范围是从 startIndex 开始,因此 i 的取值为 2 和 3。

第二次迭代,i = 2,我们将 2 添加到 path 中:

path.add(2); // path = [1, 2]

再次进行递归调用:

combineHelper(4, 2, 3);

进入递归后,判断 path 的大小是否等于 2,此时满足条件,我们将 path 的内容添加到 result 中:

result.add(new ArrayList<>(path)); // result = [[1, 2]]

然后返回上一层递归调用,执行 path.removeLast(),将最后一个元素从 path 中移除:

path.removeLast(); // path = [1]

回到第一次迭代,继续循环,此时 i = 3:

path.add(3); // path = [1, 3]

再次进行递归调用:

combineHelper(4, 2, 4);

进入递归后,判断 path 的大小是否等于 2,此时满足条件,将 path 的内容添加到 result 中:

result.add(new ArrayList<>(path)); // result = [[1, 2], [1, 3]]

返回上一层递归调用,执行 path.removeLast():

path.removeLast(); // path = [1]

回到初始调用的位置,进行下一次迭代,此时 startIndex 为 2:

combineHelper(4, 2, 3);

进入递归后,判断 path 的大小是否等于 2,此时不满足条件,继续进行循环。循环只有一次,i = 3,我们将 3 添加到 path 中:

path.add(3); // path = [1, 3]

再次进行递归调用:

combineHelper(4, 2, 4);

进入递归后,判断 path 的大小是否等于 2,此时满足条件,将 path 的内容添加到 result 中:

result.add(new ArrayList<>(path)); // result = [[1, 2], [1, 3], [1, 4]]

返回上一层递归调用,执行 path.removeLast():

path.removeLast(); // path = [1]

回到初始调用的位置,进行下一次迭代,此时 startIndex 为 3。因为 startIndex 大于 n - (k - path.size()) + 1,不满足循环条件,第一次递归调用结束。

返回到 combine 方法,此时 result 中存储了所有的组合结果。

最终返回 result:

return result; // [[1, 2], [1, 3], [1, 4]]

重复上述步骤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/562097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第四十九天学习记录:C语言进阶:结构体

结构体 结构体的声明 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 struct tag {member-list; }variable-list;问&#xff1a;C的new和C语言的结构体有什么异同&#xff1f; ChatAI答&#xff1a; C中的new是一个运算符&#xff…

Scrum的三个工件(产品Backlog、Sprint Backlog、产品增量 )

产品Backlog •产品backlog是一个按照价值排序的需求清单。 •为了达成产品目标&#xff0c;所有的需求都需要放到产品backlog中进行管理和规划。 •由产品负责人负责管理和维护。 产品Backlog当中的工作按照迭代的方式推进 •在Scrum中Sprint&#xff08;冲刺&#xff09…

Spring Security 中的过滤器链是什么?它的作用是什么

Spring Security是一个安全框架&#xff0c;它提供了强大的安全保护功能&#xff0c;可以帮助开发者更加方便地实现应用程序的安全性。Spring Security中的过滤器链是其中一个非常重要的部分&#xff0c;它起到了非常重要的作用。本文将介绍什么是Spring Security中的过滤器链&…

经典JavaScript手写面试题和答案

文章目录 实现一个函数去重&#xff1f;实现一个函数&#xff0c;判断指定元素在数组中是否存在&#xff1f;实现一个函数&#xff0c;将给定字符串反转&#xff1f;实现一个函数&#xff0c;检测指定字符串是否为回文&#xff08;即从前往后和从后往前的字符序列都相同&#x…

【30天熟悉Go语言】2 Go开发环境搭建、Hello World程序运行

文章目录 一、前言二、安装和配置SDK1、安装2、环境配置 三、开发工具1、GoLand2、VS Code 四、Hello World程序通过命令运行1&#xff09;go build2&#xff09;go run 1、Go 和 Java的文件结构对比2、Go和Java常用包对比 五、Go执行流程1、先编译再运行2、一次性编译运行区别…

一、尚医通登录需求

文章目录 一、登录需求1、登录效果2、登录需求 二、登录1&#xff0c;搭建service-user模块1.1 搭建service-user模块1.2 修改配置1.3 启动类1.4 配置网关 2、添加用户基础类2.1 添加model2.2 添加Mapper2.3 添加service接口及实现类2.4 添加controller 3、登录api接口3.1 添加…

leetcode刷题之数组问题总结,二分法,移除元素,滑动窗口相关问题,螺旋矩阵相关问题

目录 一、二分查找相关应用704.二分查找35.搜索插入位置方法一:二分法暴力解法 34.在排序数组中查找元素的开始位置和最后一个位置方法一&#xff1a;暴力解法方法二&#xff1a;二分法&#xff0c;确定左右两侧的边界 69.x的平方根方法一:二分法方法二&#xff1a;暴力解法错解…

图表控件LightningChart JS v.4.0全新发布!引入DataGrid 组件、新的颜色主题

LightningChart JS是性能最高的JavaScript图表库&#xff0c;专注于实时数据可视化。是Web上性能最高的图表库具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用&#xff0c;从而实现高刷新率和流畅的动画。…

MySQL主从同步(不开GTID)

一、背景 了解并熟悉MySQL的主从同步的搭建过程&#xff0c;并解决搭建过程中所碰到的问题。 二、目标 了解并熟悉MySQL的主从同步的搭建过程&#xff0c;并解决搭建过程中所碰到的问题。 IP地址MySQL版本主从关系192.168.3.2445.6.51Master192.168.3.2455.7.41Slaver192.16…

Flutter三棵树系列之详解各种Key | 京东云技术团队

简介 key是widget、element和semanticsNode的唯一标识&#xff0c;同一个parent下的所有element的key不能重复&#xff0c;但是在特定条件下可以在不同parent下使用相同的key&#xff0c;比如page1和page2都可以使用ValueKey(1) 。 常用key的UML关系图如上&#xff0c;整体上…

Apache Hudi 在袋鼠云数据湖平台的设计与实践

在大数据处理中&#xff0c;实时数据分析是一个重要的需求。随着数据量的不断增长&#xff0c;对于实时分析的挑战也在不断加大&#xff0c;传统的批处理方式已经不能满足实时数据处理的需求&#xff0c;需要一种更加高效的技术来解决这个问题。Apache Hudi&#xff08;Hadoop …

安科瑞对于热继电器对电动机保护的探讨

安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘要:电动机烧毁是每一个生产企业都无法回避的现象&#xff0c;怎样加强电动机保护&#xff0c;使生产工艺系统的稳定&#xff0c;减少企业非正常停机时间。电动机保护成为电气技术人员一个重要课题。因此&#xff0c…

嵌入式 QT QListWidget 显示列表视图的小部件类

目录 1. 添加对象 2. 设置间距 3. 获取内容 4. 删除对象 5.更改对象内容 在Qt框架中&#xff0c;QListWidget是一个用于显示列表视图的小部件类。它提供了一种方便的方式来显示和管理项目列表。QListWidget可以显示文本、图像和其他自定义的项目项&#xff0c;并允许用户进…

Parrot OS 5.3已经发布并可普遍下载

导读Parrot Security近日宣布&#xff0c;Parrot OS 5.3已经发布并可普遍下载&#xff0c;这是这个基于Debian的、面向红客和渗透测试者的、以安全为重点的发行版的最新稳定版本。 Parrot OS 5.3是Parrot OS 5 “Electro Ara “系列的第三部&#xff0c;在Parrot OS 5.2之后两个…

私有化部署即时通讯为什么更安全

即时通讯作为企业沟通工具&#xff0c;在企业的内部沟通和外部交流中发挥着越来越重要的作用。同时&#xff0c;企业即时通讯在提升企业内部效率的同时&#xff0c;也面临着巨大的安全威胁。 根据数据显示&#xff0c;全球有超过4亿人在使用 IM。而其中因用户隐私泄露导致的数据…

十一、数据仓库详细介绍(应用)

这是数据仓库详细介绍的最后一篇&#xff0c;后续还会在补充一些&#xff0c;把遗漏的或者没讲清楚的追加进来。 1. 前言 数据仓库是一种数据管理的方法论&#xff0c;理论概念很早就提出来了&#xff0c;而且各个行业都有广泛深入的应用。因此到目前为止该方法论的理论和实践体…

Taro小程序富文本解析4种方法

1. Taro组件rich-text 优点:使用极其方便,引用一下就行了。缺点:不支持视频,放弃!2. wxParse https://github.com/icindy/wxParse 优点:支持样式,视频缺点:进入页面图片会有由大变正常,太影响了吧。3. taro-parse https://taro-ext.jd.com/plugin/view/5e61f2acb33351…

【Netty】Netty 概述(一)

文章目录 前言一、Java原生API之痛二、Netty的优势2.1 非阻塞 I/O2.2 丰富的协议2.3 异步和事件驱动2.4 精心设计的API2.5 丰富的缓冲实现2.6 高效的网络传输 三、Netty 核心概念3.1 核心组件3.1.1 事件模型3.1.2 字节缓冲区3.1.3 通信API 3.2 传输服务3.2.1 NIO3.2.2 epoll3.2…

让数据背后的那些话创造价值 | 数据增长

从行业背景而言&#xff0c;流量红利逐渐消失&#xff0c;野蛮生长的互联网时代接近尾声。传统的烧钱模式、靠体力投放的形式日渐乏力。但是&#xff0c;企业总是要追求增长的。所以在行业大背景下&#xff0c;依靠技术和数据的力量寻求更科学、更高效的方法达成营销目标&#…

Windows系统数据结构——最小生成树、Prim算法和Kruskal算法

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows系统数据结构——最小生成树、Prim算法和Kruskal算法。 我在各在论坛看了很多相关帖子&#xff0c;发现一个简单的问题都被复杂化了。最小生成树、Prim算法和Kruskal算法真的没有大家想的…