代码随想录二刷day24 | 回溯算法 之 理论基础 77. 组合

news2024/11/24 17:58:55

day24

      • 理论基础
      • 77. 组合
        • 递归函数的返回值以及参数
        • 回溯函数终止条件
        • 单层搜索的过程

理论基础

回溯法解决的问题都可以抽象为树形结构。
因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。
递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

回溯三部曲

  • 回溯函数模板返回值以及参数

在回溯算法中,我的习惯是函数起名字为backtracking,这个起名大家随意。

回溯算法中函数返回值一般为void。

再来看一下参数,因为回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数。

但后面的回溯题目的讲解中,为了方便大家理解,我在一开始就帮大家把参数确定下来。

回溯函数伪代码如下:

void backtracking(参数)
  • 回溯函数终止条件

既然是树形结构,那么我们在讲解二叉树的递归的时候,就知道遍历树形结构一定要有终止条件,所以回溯也有要终止条件。

什么时候达到了终止条件,树中就可以看出,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。

所以回溯函数终止条件伪代码如下:

if (终止条件) {
    存放结果;
    return;
}
  • 回溯搜索的遍历过程

在上面我们提到了,回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度。

如图:
在这里插入图片描述

注意图中,我特意举例集合大小和孩子的数量是相等的!

回溯函数遍历过程伪代码如下:

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

for循环就是遍历集合区间,可以理解一个节点有多少个孩子,这个for循环就执行多少次。

backtracking这里自己调用自己,实现递归。

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

分析完过程,回溯算法模板框架如下:

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

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

77. 组合

题目链接
解题思路:
在这里插入图片描述可以看出这棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不再重复取。

第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。

每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围。
图中可以发现n相当于树的宽度,k相当于树的深度。

那么如何在这个树上遍历,然后收集到我们要的结果集呢?

图中每次搜索到了叶子节点,我们就找到了一个结果。

相当于只需要把达到叶子节点的结果收集起来,就可以求得 n个数中k个数的组合集合。
回溯三部曲:

递归函数的返回值以及参数

在这里要定义两个全局变量,一个用来存放符合条件单一结果,一个用来存放符合条件结果的集合。

代码如下:

vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果

其实不定义这两个全局变量也是可以的,把这两个变量放进递归函数的参数里,但函数里参数太多影响可读性,所以我定义全局变量了。

函数里一定有两个参数,既然是集合n里面取k个数,那么n和k是两个int型的参数。

然后还需要一个参数,为int型变量startIndex,这个参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,…,n] )。

为什么要有这个startIndex呢?
startIndex 就是防止出现重复的组合。

从下图中红线部分可以看出,在集合[1,2,3,4]取1之后,下一层递归,就要在[2,3,4]中取数了,那么下一层递归如何知道从[2,3,4]中取数呢,靠的就是startIndex。
在这里插入图片描述所以需要startIndex来记录下一层递归,搜索的起始位置。

那么整体代码如下:

vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件单一结果
void backtracking(int n, int k, int startIndex)

回溯函数终止条件

什么时候到达所谓的叶子节点了呢?

path这个数组的大小如果达到k,说明我们找到了一个子集大小为k的组合了,在图中path存的就是根节点到叶子节点的路径。

如图红色部分:

在这里插入图片描述

此时用result二维数组,把path保存起来,并终止本层递归。

所以终止条件代码如下:

if (path.size() == k) {
    result.push_back(path);
    return;
}

单层搜索的过程

回溯法的搜索过程就是一个树型结构的遍历过程,在如下图中,可以看出for循环用来横向遍历,递归的过程是纵向遍历。

77.组合1
如此我们才遍历完图中的这棵树。

for循环每次从startIndex开始遍历,然后用path保存取到的节点i。

代码如下:

for (int i = startIndex; i <= n; i++) { // 控制树的横向遍历
    path.push_back(i); // 处理节点
    backtracking(n, k, i + 1); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始
    path.pop_back(); // 回溯,撤销处理的节点
}

可以看出backtracking(递归函数)通过不断调用自己一直往深处遍历,总会遇到叶子节点,遇到了叶子节点就要返回。

backtracking的下面部分就是回溯的操作了,撤销本次处理的结果。

组合问题C++完整代码如下:

class Solution {
private:
    vector<vector<int>> result; // 存放符合条件结果的集合
    vector<int> path; // 用来存放符合条件结果
    void backtracking(int n, int k, int startIndex) {
        if (path.size() == k) {
            result.push_back(path);
            return;
        }
        for (int i = startIndex; i <= n; i++) {
            path.push_back(i); // 处理节点
            backtracking(n, k, i + 1); // 递归
            path.pop_back(); // 回溯,撤销处理的节点
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        result.clear(); // 可以不写
        path.clear();   // 可以不写
        backtracking(n, k, 1);
        return result;
    }
};

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

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

相关文章

《JavaEE初阶》JVM基础知识

《JavaEE初阶》JVM基础知识 文章目录 《JavaEE初阶》JVM基础知识JVM内存区域划分堆:栈:方法区:程序计数器:划分细节: 类加载机制:双亲委派模型:垃圾回收机制(GC)什么样的内存需要GC来回收引用计数来判断对象是否是垃圾:使用可达性分析来判断对象是否为垃圾:垃圾回收策略:有缺陷…

Windows中安装和使用Kafka

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是Rockey&#xff0c;不知名企业的不知名Java开发工程师 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;联系方式&#xff1a;he18339193956&…

【大学物理实验】凸透镜焦距测定

文章目录 选择题选择题 (多选题) 光路调整与薄透镜焦距测定中用到的主要实验元件包括: A. 光具座 B. 薄凸透镜 C. 光源 D. 带有平面镜的像屏 正确答案: ABCD (多选题)光路共轴调节是将那些光学元件的几何中心调至等高: A. 光具座 B. 透镜 C. 光源 D. 带有平面镜的像屏 正确…

Pixea 5:Mac电脑看图软件

Pixea 5是一款适用于 Mac 平台的图像浏览和管理软件。 下面是关于 Pixea Mac 看图软件的简要介绍&#xff1a; 图像浏览&#xff1a;Pixea 提供快速、流畅的图像浏览功能&#xff0c;支持常见的图像格式&#xff0c;如JPEG、PNG、BMP、GIF等。您可以通过缩略图、列表视图或全屏…

万物的算法日记|第四天

笔者自述&#xff1a; 一直有一个声音也一直能听到身边的大佬经常说&#xff0c;要把算法学习搞好&#xff0c;一定要重视平时的算法学习&#xff0c;虽然每天也在学算法&#xff0c;但是感觉自己一直在假装努力表面功夫骗了自己&#xff0c;没有规划好自己的算法学习和总结&am…

IF: 25+ 单细胞转录组学揭示肝实质和非实质细胞系的早期出现

&#xff0c; 桓峰基因公众号推出单细胞生信分析教程并配有视频在线教程&#xff0c;目前整理出来的相关教程目录如下&#xff1a; Topic 6. 克隆进化之 Canopy Topic 7. 克隆进化之 Cardelino Topic 8. 克隆进化之 RobustClone SCS【1】今天开启单细胞之旅&#xff0c;述说单细…

dubbo 服务拆分和调用

序言&#xff1a;dubbo 是阿里巴巴开发的一款开源的java rpc 框架&#xff0c;也就是远程调用框架。本文将说明dubbo服务拆分的实现思路。 本文是基于黑马探花交友前置课程dubbo做出的笔记记录。 完整视频和资料 通过百度网盘分享的文件&#xff1a;黑马 链接:https://pan.bai…

win10家庭版找不到组策略gpedit.msc的解决方法

废话不多说&#xff0c; 直接上方法&#xff1b;注意的事项我会再后面讲到。 1、打开记事本 在记事本中保存如下批处理内容 echo offpushd "%~dp0"dir /b %systemroot%\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mu…

损坏的二进制文件会导致“程序太大而无法放入内存”

不知道你是否做过这样的小实验&#xff1a;将一个可执行文件的头部写入一些无效的数据&#xff0c;或者将一个根本不是可执行文件的大型文件的扩展名改为”.exe”&#xff0c;然后执行它(警告&#xff0c;请记得先保存好工作文件)。 文件不会如预期般那样执行&#xff0c;你会…

【Python 随练】不相同的三位数字

题目&#xff1a; 有 1、2、3、4 个数字&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;在控制台输出出来。 简介&#xff1a; 在本篇博客中&#xff0c;我们将使用Python代码解决一个数学问题&#xff1a;如何使用数字1、2、3和4组合成互不相同且无重复…

Vue 常用指令

指令介绍 指令 : 带有 v- 前缀的特殊属性。 指令的作用 : 当表达式的值改变时&#xff0c;将其产生的连带影响&#xff0c;响应式地作用于 DOM 。 在整个vue的编写过程当中&#xff0c;只要带v-的&#xff0c;那么都是常用的vue的指令。 v-text v-text作用与双大花括号作用…

【已解决】“X-Content-Type-Options”头缺失或不安全

Appscan是一款安全漏洞扫描软件&#xff0c;由IBM公司研发&#xff0c;后又被卖给了印度公司HCL。 在web安全测试中&#xff0c;今天我们说下扫描结果中包含X-Content-Type-Options请求头header的缺失或不安全的时候&#xff0c;我们该如何应对。 风险&#xff1a;可能会收集…

华为OD机试真题 JavaScript 实现【猴子爬山】【2023 B卷 100分】,附详细解题思路

一、题目描述 一天一只顽猴想去从山脚爬到山顶&#xff0c;途中经过一个有个N个台阶的阶梯&#xff0c;但是这猴子有一个习惯&#xff1a; 每一次只能跳1步或跳3步&#xff0c;试问猴子通过这个阶梯有多少种不同的跳跃方式&#xff1f; 二、输入描述 输入只有一个整数N&…

使用Linux系统命令对后门端口进行查杀

第一步&#xff0c;打开网络拓扑&#xff0c;启动实验虚拟机&#xff0c;查看虚拟机IP地址&#xff1a; Centos Linux 第二步&#xff0c;进入靶机服务器CentOS Linux&#xff0c;调用实验环境。使用docker images命令查看靶机服务器上的Docker镜像环境&#xff0c;找到本次实…

《水经注地图服务》横向扩展部署说明

在地图服务器中&#xff0c;随着数据量的不断增大&#xff0c;可能会存在原有的存储设备空间不够的情况&#xff0c;或无法承受高并发请求的情况。 此时&#xff0c;我们就可以通过横向扩展部署&#xff0c;增加新的设备来进行分担缓减&#xff0c;从而达到动态扩展存储设备以…

华为流程体系:IPD流程框架(限制版)

目录 前言 详细内容 专栏列表 CSDN学院课程地址 前言 今天主要来谈谈 IPD 体系的主体框架所涉及的一些相关内容。 其实关于 IPD 体系&#xff0c;我在之前的文章或课程中都有过不同程度的讲解。 但是&#xff0c;由于这个体系所涉及的面是非常广泛的。 这个时候就必须通…

加固你的数据防线:避免成为SQL注入攻击的下一个目标

SQL注入是一种常见的Web应用程序安全漏洞&#xff0c;攻击者利用该漏洞通过构造恶意的SQL查询语句&#xff0c;以执行未经授权的操作或获取敏感数据。本文将介绍SQL注入的概念、攻击原理以及常见的防范方案&#xff0c;帮助开发人员和系统管理员加强对Web应用程序的安全性。 1、…

深入理解迭代器,笛卡尔积,from itertools import product 小白一看就会

文章目录 一、product()是什么&#xff1f;二、product()的具体使用案例代码详细分析 总结 一、product()是什么&#xff1f; 在Python中&#xff0c;product()是内置函数itertools提供的一个工具函数&#xff0c;可以计算多个可迭代对象的笛卡尔积。product()接受一个或多个可…

7、微服务组件gateway

1、引入gateway 在原来的项目中添加gateway模块 gateway是springcloud中的组件&#xff0c;所以要确保父项目的pom.xml中引入了springcloud 那么在gateway模块的pom.xml中引入gateway&#xff0c;如下&#xff1a; <?xml version"1.0" encoding"UTF-8&quo…

Jmeter集成到jenkins

Jmeter集成到Jenkins 序号 修改人 版本 创建日期 修改日期 备注 1 进击的雷神 V1.0 Jmeter集成到Jenkins. 1 软件下载... 4 一:环境配置... 4 1.JDK安装&#xff…