【数据结构与算法】递归、回溯、八皇后 一文打尽!

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《数据结构与算法:初学者入门指南》📘📘

本专栏纯属为爱发电永久免费!!!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net

目录

递归

引言:

第一部分:什么是递归算法?

第二部分:递归算法的基本原理

第三部分:递归算法的应用场景——一个小故事

第四部分:递归算法在开发中的应用和经典问题

在面试中,递归算法经常被用作考察候选人的问题解决能力和算法思维。以下是一些经典的使用递归的面试问题:

迷宫问题

代码的逻辑如下:

是否发现一个问题:

那就再进一步 到了回溯 最经典的八皇后问题

回溯:

思想:

方法:

八皇后:

优化思路:

我们可以用一维数组来表示这个皇后棋盘  arr[8]的八个值就是  八个皇后的横坐标 (因为我们已经知道他们不会同行,即纵坐标默认不相同)

具体步骤如下:

代码 实现:

测试结果​


递归

引言:


递归算法是计算机科学中一种强大而又神秘的概念。它的简洁性和优雅性使得它在许多领域都得到广泛应用,例如数学、计算机科学和算法设计。本文将带你一起探索递归算法的精髓,解开其无限奥秘。

第一部分:什么是递归算法?


递归算法是一种自引用的算法,它通过将大问题分解为更小的相似子问题来解决复杂的计算任务。递归算法的核心思想在于将一个问题分解为一个或多个基本情况和一个或多个规模较小但同样结构的子问题。这些子问题将继续被分解,直到达到基本情况,然后逐层返回结果,最终解决原始问题。

第二部分:递归算法的基本原理

在使用递归算法时,我们需要明确两个关键要素:基本情况和递归关系。

  1. 基本情况:基本情况是指递归过程中的终止条件。当问题达到基本情况时,递归停止,直接返回结果。基本情况的定义必须确保问题规模足够小,可以直接求解。
  2. 递归关系:递归关系定义了如何将原始问题分解为规模较小但同样结构的子问题。通过递归关系,我们能够将问题逐步分解,并将子问题的解合并为原始问题的解。

第三部分:递归算法的应用场景——一个小故事

从前有座山山里有座庙,庙里有个小和尚。这个小和尚喜欢讲故事,有一天他开始讲了一个故事:“从前有座山山里有座庙,庙里有个小和尚,小和尚再说一个故事 故事的内容是...”

这个故事似乎永远没有结束的样子。听众们开始思考,这个故事是如何结束的呢?

递归的思想在这个故事中展现得淋漓尽致。小和尚讲的故事不断重复,每次故事的结尾都是开始的部分,形成了一个无限循环的过程。这种无限循环的特性正是递归的本质。

在这个故事中,小和尚讲的故事本身就是一个子问题,而每个子问题又以同样的方式继续展开,不断地迭代下去。

第四部分:递归算法在开发中的应用和经典问题

递归算法在开发中有广泛的应用。它可以用来解决各种问题,包括但不限于以下情况:

  • 树和图的遍历:递归算法可以应用于树和图的深度优先搜索(DFS)和广度优先搜索(BFS)等遍历算法。
  • 排列和组合:递归算法可以生成所有可能的排列和组合,如全排列、子集生成等。
  • 分治算法:递归算法可以将一个大问题分解为多个子问题,并将子问题的解合并为整体解,如归并排序、快速排序等。
  • 动态规划:递归算法可以用于解决动态规划问题,通过将问题分解为子问题,并保存子问题的解,避免重复计算,提高效率。

在面试中,递归算法经常被用作考察候选人的问题解决能力和算法思维。以下是一些经典的使用递归的面试问题:

  • 阶乘计算:使用递归算法计算给定数的阶乘。
  • 斐波那契数列:使用递归算法生成斐波那契数列的第n项。
  • 二叉树相关问题:如二叉树的遍历、判断是否为二叉搜索树等。
  • 字符串处理:如字符串反转、判断回文串等。

第五部分:用Java实现递归
下面是一个简单的Java代码示例,用于计算给定数的阶乘:

public class RecursionExample {public static int factorial(int n) {// 基本情况:当n为0或1时,直接返回1if (n == 0 || n == 1) {return 1;}// 递归关系:将问题分解为规模较小的子问题return n * factorial(n - 1);}public static void main(String[] args) {int number = 5;int result = factorial(number);System.out.println("Factorial of " + number + " is: " + result);}
}

这个比较简单 那我们就继续引入一个较为复杂一点的案例

迷宫问题

迷宫问题是一个经典的应用递归思想的例子。它通常描述为在一个二维的迷宫中,从起点到达终点的路径规划问题。现在我们来说明如何通过递归来分析和解决迷宫问题。

  1. 问题分析:

    • 首先,我们需要明确问题的输入和输出。在迷宫问题中,输入是一个迷宫地图,包含起点、终点以及障碍物的位置信息。输出是一条从起点到终点的路径,或者判断是否存在可行路径。
    • 其次,我们要考虑如何表示迷宫和路径。通常我们可以使用二维数组或矩阵表示迷宫,其中不可通过的区域可以用特定的符号或数字表示。路径可以用一个列表或栈来保存经过的位置。
    • 最后,我们需要定义问题的规模和边界条件。规模是指迷宫的大小,边界条件是指起点和终点的位置是否在合法范围内。
  2. 解决问题:

    • 首先,我们要确定递归函数的定义和结束条件。在迷宫问题中,可以定义一个递归函数来搜索路径,每次尝试从当前位置向上下左右四个方向移动,直到达到终点或无法继续移动为止。
    • 接下来,我们需要考虑递归函数的递归关系。在迷宫问题中,递归关系可以描述为:如果当前位置可通过且未被访问过,则将当前位置标记为已访问,并尝试向四个方向递归搜索路径。
    • 最后,我们要处理递归函数的返回值。如果找到一条路径,则返回该路径;如果无法找到路径,则返回空值或特定的标识。

我们先把这个迷宫用二维数组画出来:

// 先创建一个二维数组,模拟迷宫// 地图int[][] map = new int[8][7];// 使用1 表示墙// 上下全部置为1for (int i = 0; i < 7; i++) {map[0][i] = 1;map[7][i] = 1;}// 左右全部置为1for (int i = 0; i < 8; i++) {map[i][0] = 1;map[i][6] = 1;}//设置挡板, 1 表示map[3][1] = 1;map[3][2] = 1;

/*** * @param map 表示地图* @param i 从哪个位置开始找* @param j * @return 如果找到通路,就返回true, 否则返回false*/public static boolean setWay(int[][] map, int i, int j) {if(map[6][5] == 2) { // 通路已经找到okreturn true;} else {if(map[i][j] == 0) { //如果当前这个点还没有走过//按照策略 下->右->上->左  走map[i][j] = 2; // 假定该点是可以走通.if(setWay(map, i+1, j)) {//向下走return true;} else if (setWay(map, i, j+1)) { //向右走return true;} else if (setWay(map, i-1, j)) { //向上return true;} else if (setWay(map, i, j-1)){ // 向左走return true;} else {//说明该点是走不通,是死路map[i][j] = 3;return false;}} else { // 如果map[i][j] != 0 , 可能是 1, 2, 3return false;}}}

代码的逻辑如下:

  1. 首先检查当前位置 (i, j) 是否为目标位置 (6, 5),如果是,说明已经找到通路,返回 true
  2. 如果当前位置不是目标位置,那么再判断当前位置是否可走(map[i][j] == 0)。如果是可走的,继续执行下面的步骤;否则返回 false
  3. 将当前位置标记为已经走过(map[i][j] = 2)。
  4. 依据下、右、上、左的顺序,依次尝试向四个方向移动。
    • 如果向下移动 (setWay(map, i+1, j)) 返回 true,说明找到了通路,直接返回 true
    • 如果向右移动 (setWay(map, i, j+1)) 返回 true,说明找到了通路,直接返回 true
    • 如果向上移动 (setWay(map, i-1, j)) 返回 true,说明找到了通路,直接返回 true
    • 如果向左移动 (setWay(map, i, j-1)) 返回 true,说明找到了通路,直接返回 true
  5. 如果以上四个方向都没有找到通路,说明该点是走不通的,将该位置标记为死路(map[i][j] = 3),并返回 false
  6. 如果当前位置不可走(map[i][j] != 0),直接返回 false

整个算法通过递归的方式,在每个位置上尝试四个方向的移动,直到找到通路或者所有路径都被尝试完毕。如果找到通路,返回 true,否则返回 false。在每次递归调用时,都会改变地图的状态,标记已经走过的路径,以及死路。

是否发现一个问题:

这个代码只按照了其中一种策略(即下 右 上 左的策略)  这样出来的路径就不一定是最短的  如果需要优化就要用到后面的贪心算法 到时候会专门出一期贪心算法的讲解。

但是这里我们要讲解的是这个递归的思路 可以非常简洁的解决了问题

那就再进一步 到了回溯 最经典的八皇后问题

回溯:

思想:

回溯是一种经典的算法思想,常用于解决在给定的搜索空间中找到所有可能解的问题。它的基本思想是通过尝试不同的选择,当发现当前选择并不是有效的解决方案时,回溯到上一步并尝试其他选择,直到找到所有的解或者确定不存在解。

方法:

  1. 定义问题的解空间:确定问题的解可以表示为一棵树的结构,每个节点代表一个可能的解,通过在树上进行深度优先搜索来遍历所有可能的解。

  2. 定义候选集:确定每个节点的子节点是什么。候选集表示在当前节点上可以进行选择的所有可能选项。

  3. 编写递归函数:递归函数负责遍历解空间树。在每个节点上,递归函数检查当前节点是否是一个有效解决方案,如果是,则将其添加到结果集中。然后,递归地调用自身来继续探索下一个节点。

  4. 定义结束条件:在递归函数中,定义结束条件来判断是否到达了解空间的叶子节点或满足特定条件的节点。当满足结束条件时,递归函数停止递归,回溯到上一步进行其他选择。

  5. 回溯:在递归函数中,当发现当前选择不是有效解决方案时,需要回溯到上一步并尝试其他选择。回溯是通过撤销对当前节点的选择,恢复到上一步状态,并继续遍历其他可能的选择

八皇后:

八皇后问题是一个经典的组合问题,其目标是在一个8×8的棋盘上放置8个皇后,使得任意两个皇后都不能互相攻击,即不能在同一行、同一列或同一对角线上。

解决八皇后问题的思路如下:

  1. 定义问题的解空间:在每一行放置一个皇后,每个皇后的位置可以表示为一个二维坐标 (row, col),其中 row 表示行数,col 表示列数。因为每一行只能放置一个皇后,所以解空间可以看作是一个排列问题。

  2. 定义候选集:候选集表示每个节点上可以进行选择的所有可能选项。对于每一行,皇后可以放置在该行的任意列上,所以候选集为 [0, 7],表示列的范围。

  3. 编写递归函数:递归函数负责遍历解空间树。在每个节点上,递归函数检查当前节点的选择是否满足不攻击的条件,如果是,则将其添加到结果集中。然后,递归地调用自身来继续探索下一行的选择。

  4. 定义结束条件:在递归函数中,定义结束条件来判断是否已经放置了所有的皇后。当所有的皇后都被放置时,递归函数停止递归,回溯到上一行进行其他选择。

  5. 回溯:在递归函数中,当发现当前选择不满足不攻击的条件时,需要回溯到上一列并尝试其他选择。回溯是通过撤销对当前节点的选择,恢复到上一步状态,并继续遍历其他可能的选择。

优化思路:

我们可以用一维数组来表示这个皇后棋盘  arr[8]的八个值就是  八个皇后的横坐标 (因为我们已经知道他们不会同行,即纵坐标默认不相同)

  1. 定义问题的解空间:使用一个一维数组 arr,其中 arr[i] 表示第 i 行皇后的列位置。因为每一行只能放置一个皇后,所以解空间可以看作是一个排列问题。

  2. 定义候选集:候选集表示每个节点上可以进行选择的所有可能选项。对于每一行,皇后可以放置在该行的任意列上,所以候选集为 [0, 7],表示列的范围。

  3. 编写递归函数:递归函数负责遍历解空间树。在每个节点上,递归函数检查当前节点的选择是否满足不攻击的条件,如果是,则将其添加到结果集中。然后,递归地调用自身来继续探索下一行的选择。

  4. 定义结束条件:在递归函数中,定义结束条件来判断是否已经放置了所有的皇后。当所有的皇后都被放置时,递归函数停止递归,回溯到上一行进行其他选择。

  5. 回溯:在递归函数中,当发现当前选择不满足不攻击的条件时,需要回溯到上一列并尝试其他选择。回溯是通过撤销对当前节点的选择,恢复到上一步状态,并继续遍历其他可能的选择。

具体步骤如下:

  1. 初始化一个长度为 8 的一维数组 arr,将其所有元素初始化为 0

  2. 从第一行开始逐行放置皇后,调用递归函数 backtrack(arr, 0),其中第二个参数表示当前放置的行数。

  3. 在递归函数 backtrack 中,首先判断是否已经放置了所有的皇后(即当前行数等于总行数),如果是,则将 arr 添加到结果集中。

  4. 否则,遍历当前行的所有列,依次尝试放置皇后。对于每个位置,判断是否与已经放置的皇后冲突,如果不冲突,则将该位置记录到 arr 中,然后递归调用 backtrack(arr, row + 1) 进行下一行的放置。

  5. 在回溯过程中,要记得撤销对当前节点的选择,即将 arr[row] 的值恢复为 -1,以便尝试其他选择。

  6. 最终,返回结果集,即所有满足条件的皇后位置组合。

代码 实现:

public class Queue8 {static int MaxSize=8;static int[] arr=new int[MaxSize];static int count =0;public static void main(String[] args) {check(0);System.out.println("count:"+count);}/***description<放置第n个皇后>* @param n 第n个皇后* @return void* @author SUZE* @time 2024/2/18-18:56*/public static void check(int n){if (n==8){//每当n为8意味着已经放置了8个皇后了,因为其实0~7才是需要检验的printf();count++;return;}for (int i=0;i<MaxSize;i++){//先把第n个皇后 放在该行的第i列arr[n]=i;if (judge(arr,n)){check(n+1);//满足了则继续下一位}}}
/***description<功能描述>[arr, i, n] 放置前n个皇后有无冲突* @return boolean* @author SUZE* @time 2024/2/18-18:57*/public static boolean judge(int[] arr,int n) {for (int i=0;i<n;i++){// 同列皇后情况   两皇后处在斜线的情况 (即纵坐标之差等于横坐标之差 因为可能包含了四个象限所以用绝对值)if (arr[i]==arr[n]||Math.abs(arr[i]-arr[n])==Math.abs(i-n)){return false;}}return true;}public static void printf(){for (int i=0;i<MaxSize;i++){System.out.printf("%d ",arr[i]);}System.out.println();}}

测试结果

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

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

相关文章

Vue3+Vite+TS+Pinia+ElementPlus+Router+Axios创建项目

目录 初始项目组成1. 创建项目1.1 下载项目依赖1.2 项目自动启动1.3 src 别名设置vite.config.ts配置文件tsconfig.json配置若新创项目ts提示 1.4 运行测试 2. 清除默认样式2.1 样式清除代码下载2.2 src下创建公共样式文件夹style2.3 main.js中引入样式2.4 安装sass解析插件 2.…

SNAT 与 DNAT

1.SNAT 1.1 SNAT 定义 SNAT 又称源地址转换。源地址转换是内网地址向外访问时&#xff0c;发起访问的内网ip地址转换为指定的ip地址&#xff08;可指定具体的服务以及相应的端口或端口范围&#xff09;&#xff0c;这可以使内网中使用保留ip地址的主机访问外部网络&#xff…

Leetcode 145.二叉树的后序遍历

题目 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root…

应用回归分析:岭回归

岭回归&#xff0c;也称为Tikhonov正则化&#xff0c;是一种专门用于处理多重共线性问题的回归分析技术。多重共线性是指模型中的自变量高度相关&#xff0c;这种高度的相关性会导致普通最小二乘法&#xff08;OLS&#xff09;估计的回归系数变得非常不稳定&#xff0c;甚至无法…

32、IO/对文件读写操作相关练习20240218

一、使用fgets统计给定文件的行数 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h>int main(int argc, const char *argv[]) {FILE *fpNULL;if((fpfopen("./1.txt","r"))NULL)//只读形式打开1.txt文件{per…

【C++】类与对象【定义、访问限定符、this指针】

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 面向过程和面向对象初步认识 类的引入 类的定义 成员变量命名规则的建议&#xff1a; 类的访问限定符及…

见智未来:数据可视化引领智慧城市之潮

在数字时代的浪潮中&#xff0c;数据可视化崭露头角&#xff0c;为打造智慧城市注入了强大的活力。不再被深奥的数据所束缚&#xff0c;我们通过数据可视化这一工具&#xff0c;可以更加接近智慧城市的未来。下面我就以可视化从业者的角度来简单聊聊这个话题。 数据可视化首先为…

模型超参数寻优

参考某篇QSAR的sci论文设置 根据上图&#xff0c;我设置我的XGBoost模型&#xff1a; # 定义要搜索的超参数的候选值 param_grid {model__learning_rate: [0.1, 0.01, 0.001], # 调整学习率model__n_estimators: [50, 100, 200, 300,400,500], # 调整树的数量model__max_de…

防御第五次作业

拓扑图及要求 1 创建安全区域 创建nat策略 测试 2 创建目标nat 测试 3 配置双向nat 配置IP 测试 查看会话表 4 FW1 FW3 结果 5 办公区限流 销售部限流 6 7

ansible自动化运维工具及常见模块的使用

目录 一、ansible概述 二、ansible的特性 三、ansible 环境安装部署 管理端安装 ansible&#xff1a; 配置主机清单&#xff1a; 配置密钥对验证&#xff1a; 四、ansible 常见模块的使用 1&#xff0e;command 模块 2&#xff0e;shell 模块 3&#xff0e;cron 模块…

拿捏c语言指针(中)

前言 书接上回 拿捏c语言指针&#xff08;上&#xff09; 此篇主要讲解的是指针与数组之间的爱恨情仇&#xff0c;跟着我的脚步一起来看看吧~ 创造不易&#xff0c;可以帮忙点点赞吗 如有差错&#xff0c;欢迎指出 理解数组名 数组名是首元素地址 例外 1.sizeof&#xff0…

【工作向】版本管理-IPD流程简介

1. IPD的由来 Integrated Product Development&#xff0c;集成产品开发 从IBM引进并结合自身实践 2. 引入IPD的过程 突破期 -> 全面推行期 -> 与时俱进发展 -> IPD2.0 19年开始 版本 -> 项目 -> 产品 产品开发流程&#xff0c;需求管理流程&#xff0c;生…

2024最新软件测试八股文(答案+文档)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行&a…

运行错误(竞赛遇到的问题)

在代码提交时会遇见这样的错误&#xff1a; 此处运行错误不同于编译错误和答案错误&#xff0c;运行错误是指是由于在代码运行时发生错误&#xff0c;运行错误可能是由于逻辑错误、数据问题、资源问题等原因引起的。这些错误可能导致程序在运行时出现异常、崩溃。 导致不会显示…

机器学习2---逻辑回归(基础准备)

逻辑回归是基于线性回归是直线分的也可以做多分类 ## 数学基础 import numpy as np np.pi # 三角函数 np.sin() np.cos() np.tan() # 指数 y3**x # 对数 np.log10(10) np.log2(2) np.e np.log(np.e) #ln(e)# 对数运算 # log(AB) log(A) logB np.log(3*4)np.log(3)np.log(4) #…

Linux之Shell

第 1 章 Shell 概述 1&#xff09;Linux 提供的 Shell 解析器有 [zhaohadoop101 ~]$ cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh2&#xff09;bash 和 sh 的关系 [zhaohadoop101 bin]$ ll | grep bash -rwxr-xr-x. 1 root root 941880…

如何利用测评自养号成功运营沃尔玛、阿里国际等跨境平台?

沃尔玛&#xff0c;自1962年成立以来&#xff0c;已稳居全球最大零售商的行列&#xff0c;并连续多年荣登世界500强企业的榜单。凭借强大的企业实力和卓越的市场表现&#xff0c;该公司在美国《财富》杂志2014-2016年全球最大500家公司的评选中荣登榜首。如今&#xff0c;沃尔玛…

VFH特征的使用(一)

一、SHOT特征描述符可视化 C #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d_omp.h> #include <pcl/registration/correspondence_estimation.h> #include <boo…

王力宏胜诉,事实胜于雄辩,真相终将大白。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 好的&#xff0c;以下是对“2月5日&#xff0c;王力宏工作室在…

echarts制作两个柱状图

let colorList[#02ce8b,#ffbe62,#f17373]; let data1 [90,80,70,50] option { title:[{ // 第一个标题text: 环保检测, // 主标题textStyle: { // 主标题样式color: #333,fontWeight: bold,fontSize: 16},left: 20%, // 定位到适合的位置top: 10%, // 定位到适合的位置},{ //…