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

文章目录

  • 回溯算法
    • 如何理解回溯算法
    • 回溯法模版
    • 回溯算法模版框架
  • 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.mfbz.cn/a/548610.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mysql面试题 二

超键、候选键、主键、外键分别是什么&#xff1f; 超键&#xff1a;在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键&#xff0c;多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。候选键&#xff1a;是最小超键&#xff0c;即没…

【Altium Designer 20 笔记】PCB板框

Altium Designer中设置PCB板框 PCB板框位于Mechanical1层 点击放置中的线条或使用其他绘图工具来绘制板框, 可以绘制矩形、圆形或其他形状的板框,确保板框是闭合的 注意&#xff1a;在绘制板框时&#xff0c;确保线条的起点和终点相连&#xff0c;形成一个闭合的图形。 快捷键D…

【C++航海王:追寻罗杰的编程之路】异常——错误处理方式之一

目录 引言 1 -> C语言传统的处理错误的方式 2 -> C异常概念 3 -> 异常的使用 3.1 -> 异常的抛出和捕获 3.2 -> 异常的重新抛出 3.3 -> 异常规范 4 -> 自定义异常体系 5 -> C标准库的异常体系 6 -> 异常的优缺点 引言 在C编程中&#xff…

C++ | Leetcode C++题解之第32题最长有效括号

题目&#xff1a; 题解&#xff1a; class Solution { public:int longestValidParentheses(string s) {int left 0, right 0, maxlength 0;for (int i 0; i < s.length(); i) {if (s[i] () {left;} else {right;}if (left right) {maxlength max(maxlength, 2 * ri…

单细胞分析|映射和注释查询数据集

reference映射简介 在本文中&#xff0c;我们首先构建一个reference&#xff0c;然后演示如何利用该reference来注释新的查询数据集。生成后&#xff0c;该reference可用于通过cell类型标签传输和将查询cell投影到reference UMAP 等任务来分析其他查询数据集。值得注意的是&am…

做一个好的程序员难吗?只需要这10个习惯

在这个世界上&#xff0c;有数以百万计的人对软件开发充满热情&#xff0c;他们有很多名字&#xff0c;如软件工程师、程序员、编码员、开发人员。一段时间后&#xff0c;这些人可能会成为一名优秀的编码员&#xff0c;并且他们将非常熟悉如何使用计算机语言完成工作。但是&…

【LeetCode】 2724. 排序方式

排序方式 给定一个数组 arr 和一个函数 fn&#xff0c;返回一个排序后的数组 sortedArr。你可以假设 fn 只返回数字&#xff0c;并且这些数字决定了 sortedArr 的排序顺序。sortedArr 必须按照 fn 的输出值 升序 排序。 你可以假设对于给定的数组&#xff0c;fn 不会返回重复的…

记录Python链接mysql的数据库的2种操作方式

一、使用pymysql库方式 import pymysqldb pymysql.connect(hostlocalhost,userroot,password123456) #创建链接&#xff0c;在3.8以后好像已经不支持这个种链接方式了&#xff0c; #db pymysql.connect(localhost,root,123456) cursor db.cursor()#拿到游标这样我们就拿到了…

DataX-Web,介绍-安装-部署-启动

使用文档&#xff1a;GitHub - WeiYe-Jing/datax-web: DataX集成可视化页面 目录 1、DataX-Web介绍 2、DataX-Web部署 3、DataX-Web启动命令 1、DataX-Web介绍 GitHub - WeiYe-Jing/datax-web&#xff1a;DataX集成可视化页面&#xff0c;选择数据源即可一键生成数据同步任务…

iOS依赖库版本一致性检测:确保应用兼容性

一、背景 在 iOS 应用开发的世界里&#xff0c;每次 Xcode 更新都带来了新的特性和挑战。最近的 Xcode 15 更新不例外&#xff0c;这次升级引入了对 SwiftUI 的自动强依赖。SwiftUI最低是从 iOS 13 开始支持。 这一变化也带来了潜在的兼容性问题。如果您的项目在升级到 Xcode…

使用 npm 工具高效更新项目依赖包

团队内部会用工具定时检查包的最新版本并通知&#xff0c;以便我们及时跟进社区进展&#xff0c;避免和技术栈出现版本脱节导致无法使用最新特性和优化内容 这里只说明手动查看和更新包的主要几个命令。 npm outdated&#xff1a;检查项目中过时的依赖包及其最新版本。 npm i…

在 Vue 2 中动态赋值 img 标签的 src 属性时显示为图裂

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的全栈工程师 欢迎分享 / 收藏 / 赞 / 在看…

Java-通过Maven导入本地jar包的常用方式

1.首先创建一个用于创建jar包的项目&#xff0c;进行测试 2.测试成功后进行项目打包 3.创建一个要导入本地jar包的项目&#xff0c;在项目下创建lib目录&#xff0c;并将刚才打包好的jar包复制进去 4.在pom.xml文件中引入 5.运行测试

02-攻防世界PHP2

题目 authenticate:证明什么是真的 解题 观察题目可知&#xff0c;访问index.phps可能会有不一样的发现 http://61.147.171.105:51671/index.phps访问该链接&#xff0c;可以得到下面的界面 这里只显示出了部分代码&#xff0c;右键该界面&#xff0c;点击查看源代码&#xf…

引领软件供应链安全 比瓴科技位居安全牛全景图第一

近日&#xff0c;安全牛第十一版《中国网络安全行业全景图》正式发布&#xff0c;比瓴科技入选全景图软件供应链安全赛道中开发流程安全管理、DevSecOps和软件成分分析三个重要细分领域&#xff0c;并位居开发流程安全管控领域第一。 安全牛本次全景图研究工作于23年正式启动&a…

一文了解Activiti7

文章目录 ☃️1.1 Activiti 介绍☃️1.2 Activiti 开发流程☃️1.3 BPMN 2.0 规范是什么☃️1.4 BPMN 2.0 基本流程符号❄️❄️1.4.1 事件 Event❄️❄️1.4.2 活动❄️❄️1.4.3 网关 Gateway ☃️1.5 Activiti API 服务接口❄️❄️1.5.1 核心Service接口及其获取 ☃️1.1 A…

M2 运行 llamafile

安装llamafile很简单&#xff0c;进入官网&#xff0c;按照步骤安装运行即可。 https://github.com/Mozilla-Ocho/llamafile 下载 llava-v1.5-7b-q4.llamafile赋予运行权限chmod x llava-v1.5-7b-q4.llamafile运行 ./llava-v1.5-7b-q4.llamafile -ngl 9999 速度确实是比 olla…

HBase2.x学习笔记

文章目录 一、HBase 简介1、HBase 定义1.1 概述1.2 HBase 与 Hadoop 的关系1.3 RDBMS 与 HBase 的对比1.4 HBase 特征简要 2、HBase 数据模型2.1 HBase 逻辑结构2.2 HBase 物理存储结构2.3 HBase的表数据模型 3、HBase 基本架构3.1 Master3.2 Region Server3.3 Zookeeper3.4 HD…

哪个牌子的电视盒子好用?经销商整理线下热销电视盒子排行榜

在选购电视盒子的时候许多朋友并不了解哪个牌子的电视盒子好用&#xff0c;如何才能买到最满意的电视盒子呢&#xff1f;我身为数码实体店老板&#xff0c;做电视盒子这块有七年了&#xff0c;经常会有用户问我电视盒子相关问题&#xff0c;我按照店内销量整理了电视盒子排行榜…
最新文章