回溯算法,你“回”了吗

目录

一、什么是回溯算法

二、应用场景

三、一般解题步骤

1、确定回溯方法以及参数 

2、确定回溯的终止条件

3、确定搜索过程

四、力扣例题 

1、题目描述

2、解题思路

3、代码示例

五、总结


一、什么是回溯算法

回溯算法,又称为试探法,是一种通过穷举所有可能情况来找到问题的解的方法。回溯算法通常采用深度优先搜索的策略,从一个选择开始,不断地向某一方向前进,直到无法继续。此时,需要回退到上一步选择的其他分支继续尝试,直到找到问题的解或无法继续搜索。

回溯算法的思想源于数学中的排列组合问题,通过尝试所有的可能性来找到问题的解。与穷举搜索相比,回溯算法具有剪枝操作,可以通过一些判断条件来减少搜索的路径,提高算法的效率。

回溯算法虽然能够解决很多问题,但是,他并不是一个高效的算法。因为回溯的本质其实就是穷举所有可能,然后从这个所有可能中根据条件筛选出我们想要的结果。这其实也就是暴力搜索。不过,有些时候也是非回溯算法不能解决。

二、应用场景

回溯算法适用于一些需要尝试所有可能解的问题,常见的应用场景有以下几种:

  1. 排列组合问题:对于一些需要找出所有排列组合的问题,如全排列、组合总和、电话号码的字母组合等,使用回溯算法可以轻松解决。需要注意的是,组合和排列的区别是,组合是不考虑顺序的,而排列是考虑顺序的。组合也就是只要选出的元素相同就是同一种情况。而排列虽然选出的元素相同只要顺序不同,那就是不同的情况。

  2. 子集问题:对于一些需要找出所有子集的问题,如子集求和、子集和为定值等,使用回溯算法可以事半功倍。

  3. 图遍历问题:对于一些需要遍历图的问题,如寻找路径、寻找最短路径等,使用回溯算法可以有效地解决。

  4. 棋盘问题:对于一些需要在棋盘上放置棋子的问题,如N皇后问题、数独等,使用回溯算法可以找出所有可能的解。

三、一般解题步骤

 

1、确定回溯方法以及参数 

回溯方法一般命名backTracking,返回值一般为void,也就是不返回任何值。注意,这里说的是一般,具体需不需要返回值还需要根据具体场景来确定(比如,解数独的回溯方法就是需要有返回值的)。

而对于需要传的参数,一般是不能提前全部确定出来的。所以,我们可以先去实现这个回溯方法,然后在实现该方法的过程中,根据需要再去添加参数。

//大部分场景下回溯方法的返回类型都是void,所以这里就直接使用void
void backTracking(参数1,...,参数n)
2、确定回溯的终止条件

 所有的回溯算法都是可以抽象为树形结构的。因为,回溯算法都是从一个集合中递归的查找子集。所以,该集合的大小就是树的高度,递归的深度也就是树的深度。既然,是递归那么就一定会有终止条件。因为递归的深度就是树的高度,所以当递归到树的叶子节点也就是找到了一条满足要求的结果。当然,我们也可以通过分析题目,来将一些明显不满足要求的给提前终止,避免造成不必要的搜索,这也就是剪枝。

if (终止条件) {
    //把得到的这条满足要求的结果放到结果集中
    ..........
    return;
}
3、确定搜索过程

回溯法一般抽象出的树形结构图如下:

回溯算法遍历的一般代码如下:

#index表示下次循环的起点,也就是确定下次递归的集合
for(int i=index;i<=n;i++){
 //对当前遍历出的节点进行处理
 ...............
 //调用回溯方法,构成递归
 backtrack();
 //进行回溯操作,退回节点处理前的状态
 .............
}

所以不难得出,回溯算法中的回溯方法的一般代码:

if (终止条件) {
    //把得到的这条满足要求的结果放到结果集中
    ..........
    return;
}
#index表示下次循环的起点,也就是确定下次递归的集合
for(int i=index;i<=n;i++){
 //对当前遍历出的节点进行处理
 ...............
 //调用回溯方法,构成递归
 backtrack();
 //进行回溯操作,退回节点处理前的状态
 .............
}

四、力扣例题 

我们就拿力扣上面经典的回溯算法问题,51.N皇后来举例。

1、题目描述

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例 1:

示例 2:

输入:n = 1
输出:[["Q"]]

提示:

  • 1 <= n <= 9
2、解题思路

n*n的棋盘也就是一个n*n的二维数组。想要获取满足要求的结果,其实也就是需要不断试探,各种情况是否满足要求。这也就是回溯法。此时,for循环的是每一列,递归的是每一行。并且对于循环递归中已经不满足条件的,直接提前终止,避免不必要的搜索。该题抽象出来的树形结构图如下:

■  确定回溯方法以及参数

backTracking(叶子节点的结果集, 行列大小n, 当前行);

■  确定回溯的终止条件

从上面的树形图可以得知,当遍历到叶子节点或者已遍历的结果已经不能满足N皇后的要求后,便终止了。

   if (row == n) {
       res.add(arrayToList(resArray));
       return;
    }
 #这里提前进行判断了,不满足要求的就不会往下走了
 if (isValid(i, row, n, resArray)) {
     resArray[row][i] = 'Q';
     backTracking(resArray, n, row + 1);
     resArray[row][i] = '.';
  }

■  确定搜索过程

从上面的树形图可以得知,递归的深度是由棋盘的行来控制,for循环是控制棋盘的列。这样每次for循环+递归调用回溯算法的时候也就确定了在棋盘中放置皇后的位置。

 // 每列进行判断,通过递归的row来控制行数
        for (int i = 0; i < n; i++) {
            // 验证当前行为row,列为i的元素是否满足要求,满足要求的话再进行后续操作
            if (isValid(i, row, n, resArray)) {
                resArray[row][i] = 'Q';
                backTracking(resArray, n, row + 1);
                resArray[row][i] = '.';
            }
        }
3、代码示例
class Solution {
    //最终返回结果
    List<List<String>> res = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        // 定义一个n行n列的二维数组来存储叶子节点的结果
        char[][] resArray = new char[n][n];
        // 初始化二维数组,默认都是'.'
        for (char[] c : resArray) {
            Arrays.fill(c, '.');
        }
        backTracking(resArray, n, 0);
        return res;
    }

    // 回溯方法
    public void backTracking(char[][] resArray, int n, int row) {
        // 终止条件
        // 这里为什么是用的row不是row+1,是因为回溯传过来的就是已经+1了
        if (row == n) {
            res.add(arrayToList(resArray));
            return;
        }
        // 每列进行判断,通过递归的row来控制行数
        for (int i = 0; i < n; i++) {
            // 验证当前行为row,列为i的元素是否满足要求,满足要求的话再进行后续操作
            if (isValid(i, row, n, resArray)) {
                resArray[row][i] = 'Q';
                backTracking(resArray, n, row + 1);
                resArray[row][i] = '.';
            }
        }
    }

    // 定义验证方法
    public boolean isValid(int col, int row, int n, char[][] resArray) {
        // 检查同一列
        for (int i = 0; i < row; i++) {
            if (resArray[i][col] == 'Q')
                return false;
        }
        //检查45度方向
        for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
            if(resArray[i][j]=='Q')
             return false;
        }
         //检查135度方向
        for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){
            if(resArray[i][j]=='Q')
             return false;
        }
        return true;
    }

    // 定义将二维数组转换成list集合的方法
    public List<String> arrayToList(char[][] arrayChar) {
        List<String> list = new ArrayList<>();
        for (char[] c : arrayChar) {
            list.add(String.copyValueOf(c));
        }
        return list;
    }
}

五、总结

总之,回溯算法是一种在问题求解过程中遍历所有可能解的算法。它通过尝试所有可能的选择来得到问题的解,当发现选择不合适时,则进行回溯到前一步,重新选择。尽管回溯算法的时间复杂度较高,但在某些问题中,它是一种有效的解决方法。

如果对您有帮助,欢迎关注、点赞、收藏、评论! 

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

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

相关文章

用友 NC 23处接口XML实体注入漏洞复现

0x01 产品简介 用友 NC 是用友网络科技股份有限公司开发的一款大型企业数字化平台。 0x02 漏洞概述 用友 NC 多处接口存在XML实体注入漏洞,未经身份验证攻击者可通过该漏洞读取系统重要文件(如数据库配置文件、系统配置文件)、数据库配置文件等等,导致网站处于极度不安全…

【Redis】深入理解 Redis 常用数据类型源码及底层实现(5.详解List数据结构)

本文是深入理解 Redis 常用数据类型源码及底层实现系列的第5篇&#xff5e;前4篇可移步(&#xffe3;∇&#xffe3;)/ 【Redis】深入理解 Redis 常用数据类型源码及底层实现&#xff08;1.结构与源码概述&#xff09;-CSDN博客 【Redis】深入理解 Redis 常用数据类型源码及底…

Ubuntu22.04.3LTS源码编译安装ffmpeg6.x

1.官网ffmpeg下载源码 https://ffmpeg.org/download.html#build-windows 安装 libx264 开发库&#xff08;一个开源的视频压缩库&#xff0c;用于编码视频流为 H.264/MPEG-4 AVC 视频格式&#xff09;。这是编译 FFmpeg 时如果要支持 H.264 编码必须的。 sudo apt install l…

Liunx前后端项目部署(小白也可安装)

文章目录 一、CentOS服务器的安装二、jdk安装三、Tomcat安装四、MySQL安装、五、nginX安装六、多个项目负载均衡&#xff0c;部署后端项目七、前端项目部署 一、CentOS服务器的安装 选择liunx&#xff0c;下面选择CentOS 7 ![在这里插入图片描述](https://img-blog.csdnimg.cn…

预训练概念

预训练是指在特定任务之前&#xff0c;在大规模数据集上对神经网络进行训练以学习通用的表示形式或特征。这些通用表示可以捕捉数据中的统计结构和语义信息&#xff0c;使得神经网络能够更好地理解和处理输入数据。 在大规模预训练模型中&#xff0c;通常会使用无监督或弱监督的…

python脚本实现全景站点矩阵转欧拉角

效果 脚本 import re import numpy as np import math import csv from settings import * # 以下是一个示例代码,可以输入3*3旋转矩阵,然后输出旋转角度:# ,输入3*3旋转矩阵# 计算x,y,z旋转角def rotation_matrix_to_euler_angles(R):

JVM(2)

JVM类加载 指的是java进程运行时,需要把.class文件从硬盘加载到内存,并进行一系列校验解析的过程. 核心: .class文件>类对象; 硬盘>内存. 类加载过程 在整个JVM的执行流程中,和程序员关系最密切的就是类加载的过程了,所以我们来看一下类加载的执行流程. 对于一个类…

【清理mysql数据库服务器二进制日志文件】

清理前后比对 清理前占用 86% &#xff1a; 清理后占用 29% &#xff1a; 排查占用磁盘较大的文件 检测磁盘空间占用 TOP 10 # 检测磁盘空间占用 TOP 10 $ sudo du -S /var/log/ | > sort -rn | # -n选项允许按数字排序。-r选项会先列出最大数字&#xff08;逆序&#x…

Tomcat架构分析

Tomcat的核心组件 Tomcat将请求器和处理器分离&#xff0c;使用多种请求器支持不同的网络协议&#xff0c;而处理器只有一个。从而网络协议和容器解耦。 Tomcat的容器 Host&#xff1a;Tomcat提供多个域名的服务&#xff0c;其将每个域名都视为一个虚拟的主机&#xff0c;在…

git忽略某些文件(夹)更改说明

概述 在项目中,常有需要忽略的文件、文件夹提交到代码仓库中,在此做个笔录。 一、在项目根目录内新建文本文件,并重命名为.gitignore,该文件语法如下 # 以#开始的行,被视为注释. # 忽略掉所有文件名是 a.txt的文件. a.txt # 忽略所有生成的 java文件, *.java # a.j…

java演唱会网上订票购票系统springboot+vue

随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的交换和信息流通显得特别重要。因此&#xff0c;开发合适的基于springboot的演唱会购票系统的设计与实现成为企业必然要走…

【MySQL】内置函数 -- 详解

一、日期函数 日期&#xff1a;年月日时间&#xff1a;时分秒 1、获得年月日 2、获得时分秒 3、获得时间戳 4、在日期的基础上加日期 5、在日期的基础上减去时间 6、计算两个日期之间相差多少天 7、获得当前时间 ⚪练习 &#xff08;1&#xff09;记录生日 &#xff08;2&…

Qt中关于信号与槽函数的思考

信号与槽函数的思考 以pushbutton控件为例&#xff0c;在主界面上放置一个pushbutton控件&#xff0c;点击右键选择关联槽函数&#xff0c;关联一个click函数&#xff0c;如下图所示&#xff1a; 在该函数中&#xff0c;实现了一个点击pushbutton按钮后&#xff0c;弹出一个窗…

德人合科技 | 天锐绿盾终端安全管理系统

德人合科技提到的“天锐绿盾终端安全管理系统”是一款专业的信息安全防泄密软件。这款软件基于核心驱动层&#xff0c;为企业提供信息化防泄密一体化方案。 www.drhchina.com 其主要特点包括&#xff1a; 数据防泄密管理&#xff1a;天锐绿盾终端安全管理系统能够确保数据在创…

淘宝商品数据爬取商品信息采集数据分析API接口详细步骤展示(含测试链接)

01 数据采集 数据采集是数据可视化分析的第一步&#xff0c;也是最基础的一步&#xff0c;数据采集的数量和质量越高&#xff0c;后面分析的准确的也就越高&#xff0c;我们来看一下淘宝网的数据该如何爬取。点此获取淘宝API测试key&密钥 淘宝网站是一个动态加载的网站&a…

pytorch 图像的卷积操作

目录 1.卷积核基本参数说明 2.卷积相关操作说明 3.卷积操作示例 1.卷积核基本参数说明 pytorch进行图像卷积操作之前&#xff0c;需要把图像素格式进行分离&#xff0c;比如一个图像为rgb格式&#xff0c;把R&#xff0c;G,B取出来作为一个ndarray&#xff0c;前文讲过&#…

基于串流技术的p2p共享桌面共享方案

研究远控有一定时间了&#xff0c;但真正落地运用的不多&#xff0c;所以也不太上心&#xff0c;平时也只是自己diy玩玩&#xff0c;远程共享看看电视剧。 最近生成式ai大火&#xff0c;直接带动了gpu应用的相关场景&#xff0c;相关场景&#xff0c;但gpu卡又贵&#xff0c;对…

TP6上传图片到OSS(记录贴)

1&#xff0c;先安装&#xff0c;我使用composer安装 在项目的根目录运行composer require aliyuncs/oss-sdk-php 2,安装成功以后vendor目录下可以看到如图&#xff1a; 3&#xff0c;上传图片代码如下&#xff1a; <?php namespace app\controller;use app\BaseControll…

vm虚拟机的下载与安装(更新时间24/2/28)

首先进入vm官网点击跳转 进入products 进入Workstation Pro 点击DOWNLOAD TRIAL 点击DOWNLOAD NOW 到这里只需要等待下载完成就行了 安装就是正常软件程序的安装方法&#xff0c;除了自定义一下安装位置&#xff0c;其他的直接确定 许可证密钥 在网络上有很多随便一搜…

基于springboot+vue的可盈保险合同管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…