代码随想录算法训练营DAY24|C++回溯算法Part.1|回溯算法理论基础、77.组合、组合问题的剪枝操作

news2024/11/27 12:59:45

文章目录

  • 回溯算法
    • 如何理解回溯算法
    • 回溯法模版
    • 回溯算法模版框架
  • 77.组合
    • 树形结构
    • 回溯三部曲
    • 伪代码
    • CPP代码实现
  • 组合问题的剪枝操作

回溯算法

在这里插入图片描述

如何理解回溯算法

回溯法解决的问题都可以抽象为树形结构

因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度

递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

换句话来说,回溯其实是一种暴力搜索的算法,他用递归来控制for循环的

回溯法模版

  • 回溯函数的返回值及参数

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

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

但是卡哥给我们讲题的时候肯定会一开始就帮我们把参数确定下来。

回溯函数伪代码

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

既然回溯问题可以抽象成树形结构,那么遍历树形结构一定要有终止条件,所以回溯也要有终止条件。

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

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

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

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

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

回溯算法模版框架

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

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

77.组合

力扣题目链接

文章讲解:77.组合

视频讲解:带你学透回溯算法-组合问题(对应力扣题目:77.组合),组合问题的剪枝操作

状态:需要把组合问题展示成属性结构来进行组合的配对

树形结构

我们一定要把问题抽象成树形结构。

给他画一个回溯算法的搜索过程。我们可以抽象成如下树形结构

对于每一组都只取后面的数,防止重复

回溯三部曲

如何使用代码来实现呢?这里就要用到我们的回溯三部曲:

  • 复习一下之前讲的回溯模板框架

    void backtracking(参数) {
        if (终止条件) {
            存放结果;
            return;
        }
    
        for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
            处理节点;
            backtracking(路径,选择列表); // 递归
            回溯,撤销处理结果
        }
    }
    
  • 回溯三部曲:回溯算法相当于递归里面嵌套for循环

    • 递归函数的参数和返回值:因为回溯就是靠递归来实现的,所以我们称这个函数是递归函数
    • 确定递归函数的终止条件
    • 确定单层递归的逻辑,也就是单层递归的逻辑

下面按照回溯三部曲,对照着树形结构给出伪代码

伪代码

  • 递归函数的参数和返回值:
    • 返回值一般都是void
    • 由于题目要求一个组合,所以我们定义一个一维数组来存放遍历的路径path(因为我们的路径就是结果);然后定义一个result来存放各个路径的集合;但是在本题中,我们将这两个定义为全局变量,免得函数参数过多,影响可读性
    • 关于参数startIndex的强调:**我们每次递归的时候会把我们这次要搜索的其实位置传进来。**一层递归结束之后,我们在下一层递归,为了防止重复组合的出现,我们要定义好从哪开始。比如说[1, 2, 3, 4]我们把1的组合搜索光了,开始搜索2的组合时,我们应该从3开始搜索以构成[2, 3]
void backtracking(n, k, startIndex){	//n表示几个数,k表示组合的大小,startIndex
  
}
  • 确定终止条件:到了叶子结点我们要收集我们想要的结果
if (path.size == k){	//我们的path收集到k个数了,存入一次结果
  result.push(path);
  return;
}
  • 单层搜索的逻辑:每一个结点其实都是一个for循环,for循环的起始位置就是从startIndex开始,然后遍历剩余的元素。
for (i=startIndex; i <= n; i++){
  path.push(i);	//遍历完一个结点
  backtracking(n, k, ++i);
  path.pop();
}

CPP代码实现

class Solution{
private:
  vecotr<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);	//处理结点
      backracking(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;
  }
}

组合问题的剪枝操作

组合问题的剪枝操作**
拿77题举例:组合问题

如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了

所以我们这里主要瞄准的问题,就是for循环里选择的起始位置:

for (int i = startIndex; i <= n; i++){

优化过程如下:

  1. 已经选择的元素个数:path.size()
  2. 所需需要的元素个数为:k - path.size()
  3. 列表中剩余元素n - i >= 所需需要的元素个数 (k - path.size())
  4. 在集合中至多要从该起始位置开始遍历:i <= n - (k - path.size()) + 1

这里为什么要加1呢?包头包尾,其实就是左闭区间

举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。

从2开始搜索都是合理的,可以是组合[2, 3, 4]。

所以说for循环是:

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置

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

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

相关文章

Spring Boot集成Graphql快速入门Demo

1.Graphql介绍 GraphQL 是一个用于 API 的查询语言&#xff0c;是一个使用基于类型系统来执行查询的服务端运行时&#xff08;类型系统由你的数据定义&#xff09;。GraphQL 并没有和任何特定数据库或者存储引擎绑定&#xff0c;而是依靠你现有的代码和数据支撑。 优势 GraphQL…

Stable Diffusion 本地部署教程:详细步骤与常见问题解析

作为一位热衷于探索前沿AI技术的博主&#xff0c;近期我深度研究了Stable Diffusion模型的本地部署过程。在这篇教程中&#xff0c;我将详述从环境准备到模型运行的每个步骤&#xff0c;并针对常见的部署问题给出解决方案&#xff0c;帮助你顺利在本地开启Stable Diffusion的创…

pyplot+pandas实现操作excel及画图

1、安装jupyter lab pip install jupyterlab # 启动 建议在指定的项目文件夹下 开启cmd窗口并执行 jupyter lab 启动后会自动打开浏览器访问 2、安装依赖 pip install matplotlib pip install xlrd pip install pandas 3、读取excel import pandas as pddf pd.read_excel(hi…

C# Solidworks二次开发:几何公差IGot相关操作API详解

大家好&#xff0c;今天要介绍的是关于几何公差IGot相关操作的API。 几何公差之前没有讲过&#xff0c;具体API如下面所示&#xff1a; &#xff08;1&#xff09;第一个为GetText&#xff0c;这个API的含义为获取此几何公差的指定文本部分&#xff0c;下面是官方的具体解释&…

基于springboot实现医疗病历互换系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现医疗病历交互系统演示 摘要 进入21世纪&#xff0c;计算机技术迅速向着网络化的、集成化方向发展。传统的单机版应用软件正在逐渐退出舞台&#xff0c;取而代之的是支持网络、支持多种数据信息的新一代网络版应用软件&#xff0c;形成了信息化的社会。信息…

FluentUI系列 - 1 - 介绍第一个窗口

介绍一个QML的UI库&#xff0c;国人编写&#xff0c;作者也耍知乎。这个UI库确实好用&#xff0c;但是教程基本等于无&#xff0c;个人在使用中顺便记录一下学习内容。这玩意儿也有Pyside6的版本&#xff0c;有需要的可以查看PySide6-FluentUI-QML。 FluentUI库地址​github.c…

开关灯---一维数组

直接看题&#xff1a; 开关灯 此题用模拟的复杂度是O(n&#xff09; &#xff0c;其实有更优解就是用完全平方数。但是我不想在C中遇到数学。。。所以用模拟解。 把数组的类型设为bool类型即可&#xff01; AC代码&#xff1a; #include<bits/stdc.h> using namespace …

Unity TMP Inputfield 输入框 框选 富文本 获取真实定位

一、带富文本标签的框选是什么 UGUI的InputField提供了selectionAnchorPosition和selectionFocusPosition&#xff0c;开始选择时的光标下标和当前光标下标 对于未添加富文本标签时&#xff0c;直接通过以上两个值&#xff0c;判断一下框选方向&#xff08;前向后/后向前&…

前端 接口返回来的照片太大 加载慢如何解决

现象 解决 1. 添加图片懒加载 背景图懒加载 对背景图懒加载做的解释 和图片懒加载不同&#xff0c;背景图懒加载需要使用 v-lazy:background-image&#xff0c;值设置为背景图片的地址&#xff0c;需要注意的是必须声明容器高度。 <div v-for"img in imageList&quo…

麒麟 V10 离线 安装 k8s 和kuboard

目录 安装文件准备 主机准备 主机配置 修改主机名&#xff08;三个节点分别执行&#xff09; 配置hosts&#xff08;所有节点&#xff09; 关闭防火墙、selinux、swap、dnsmasq(所有节点) 安装依赖包&#xff08;所有节点&#xff09; 系统参数设置(所有节点) 时间同步…

html 引入vue Element ui 的方式

第一种&#xff1a;使用CDN的方式引入 <!--引入 element-ui 的样式&#xff0c;--> <link rel"stylesheet" href"https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <!-- 必须先引入vue&#xff0c; 后使用element-ui --> <…

Pycharm通过配置隧道连接远程服务器

前言&#xff1a; 上篇有说到局域网windows和服务器互通的情况下连接远程pycharm&#xff0c;这次咱们来说下通过跳板机的方式连接服务器如何做到windows远程连接到服务器 1&#xff1a;设置SSH隧道或SSH代理 ssh -L localhost:LOCAL_PORT:FINAL_SERVER_IP:FINAL_SERVER_PORT…

【深度学习】深入探索卷积神经网络:从基础到先进架构”

卷积神经网络&#xff1a;深度学习的视觉之眼 在过去的十年中&#xff0c;深度学习已经彻底改变了我们处理和理解图像、视频及其他视觉媒体的方式。其中&#xff0c;卷积神经网络&#xff08;CNN&#xff09;无疑是这一革命的核心。本文将带您深入了解CNN的基础知识、关键发展…

CentOS 8服务器搭建L2TP服务器(over IPsec)操作指南

正文共&#xff1a;1234 字 14 图&#xff0c;预估阅读时间&#xff1a;2 分钟 之前发过把我自己的服务器搬上公网的文章&#xff08;我用100块钱把物理服务器放到了公网&#xff0c;省了几万块&#xff01;&#xff09;&#xff0c;当时L2TP拨号用的是网络上的解决方案&#x…

MySQL 修改数据

目录 数据插入-insert 不指定列名插入&#xff1a; 插入整行数据 格式&#xff1a; 多行数据插入 格式&#xff1a; 指定列名插入 插入1行 插入多行 更新字段-update 语法&#xff1a; 删除表 语法&#xff1a; 案例&#xff1a; 数据插入-insert INSERT 将数据行…

c++命令行解析开源库cxxopts上手教程

文章目录 cxxopts快速入门1. cmake环境配置2. 定义解析的规则3. 使用例子 cxxopts 简介 cxxopts是一个轻量级的C命令行解析库&#xff0c;它提供了易于使用的API来定义和解析命令行选项。它支持多种类型的选项&#xff0c;并且允许用户自定义选项的处理逻辑。 项目地址&#x…

Unity中支持泰语--没有版权限制

在Unity中支持泰语主要涉及以下几个方面&#xff1a; 选择合适的字体&#xff1a;在Unity中&#xff0c;确保使用支持泰文字符的字体是至关重要的。例如&#xff0c;可以选择使用Noto Serif Thai字体&#xff0c;这是一个支持泰语的字体2。 处理Unity版本问题&#xff1a;某些…

【C++之queue的应用及模拟实现】

C学习笔记---014 C之queue的应用及模拟实现1、queue的简单介绍2、queue的简单接口应用3、queue的模拟实现3.1、queue的结构一般的构建3.2、queue的适配器模式构建3.3、queue的主要接口函数 4、queue的模拟实现完整代码4.1、一般方式4.2、泛型模式 5、queue巩固练习题5.1、最小栈…

软件开发安全备受重视,浙江某运营商引入CWASP认证课程,

​浙江省某大型运营商是一家实力雄厚、服务优质的通信运营商&#xff0c;致力于为全省用户提供优质、高效的通信服务。数字时代&#xff0c;该运营商顺应信息能量融合发展趋势&#xff0c;系统打造以5G、算力网络、能力中台为重点的新型信息基础设施&#xff0c;夯实产业转型升…

VUE_H5页面跳转第三方地图导航,兼容微信浏览器

当前项目是uniapp项目&#xff0c;若不是需要替换uni.showActionSheet选择api onMap(address , organName , longitude 0, latitude 0){var ua navigator.userAgent.toLowerCase();var isWeixin ua.indexOf(micromessenger) ! -1;if(isWeixin) {const mapUrl_tx "…