递归算法(JS实现代码)

news2024/9/26 3:32:06

20191109001917939

📝个人主页:爱吃炫迈
💌系列专栏:数据结构与算法
🧑‍💻座右铭:道阻且长,行则将至💗

文章目录

  • 递归算法
  • 递归的思想
  • 递归三要素
  • 递归的编程模型
  • 递归一般应用场景
  • 递归经典案例
  • 💞总结💞



递归算法

程序调用自身的编程技巧称为递归。—百度百科

我们可以这样理解递归

递归:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开它。若干次之后,你打开面前的门后,发现只有一间屋子,没有门了。然后,你开始原路返回,每走回一间屋子,你数一次,走到入口的时候,你可以回答出你到底用这你把钥匙打开了几扇门。

此时是不是有人不禁要问这难道不是循环吗 ??已晕·····

循环:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开这扇门,一直这样继续下去直到打开所有的门。但是,入口处的人始终等不到你回去告诉他答案。

通过上面的比喻相信我们已经可以发现递归的精髓(思想)是什么了


递归的思想

  • 正如上面所描述的场景,递归就是==有去(递去)有回(归来)==
  • “有去”是指:递归问题必须可以分解为若干个规模较小,与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决,就像上面例子中的钥匙可以打开后面所有门上的锁一样;
  • “有回”是指 : 这些问题的演化过程是一个从大到小,由近及远的过程,并且会有一个明确的终点(临界点),一旦到达了这个临界点,就不用再往更小、更远的地方走下去。最后,从这个临界点开始,原路返回到原点,原问题解决。733abb96393a4f2e987e82097632c622_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0

递归三要素

  1. 明确递归终止条件

我们知道,递归就是有去有回,既然这样,那么必然应该有一个明确的临界点,程序一旦到达了这个临界点,就不用继续往下递去而是开始实实在在的归来。换句话说,该临界点就是一种简单情境,可以防止无限递归。

  1. 给出递归终止时的处理方法

我们刚刚说到,在递归的临界点存在一种简单情境,在这种简单情境下,我们应该直接给出问题的解决方案。一般地,在这种情境下,问题的解决方案是直观的、容易的。

  1. 提取重复的逻辑,缩小问题规模

我们在阐述递归思想内涵时谈到,递归问题必须可以分解为若干个规模较小、与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决。从程序实现的角度而言,我们需要抽象出一个干净利落的重复的逻辑,以便使用相同的方式解决子问题。


递归的编程模型

模型一 :在递去的过程中解决问题

function recursion(大规模){ 
if (end_condition){ 
// 明确的递归终止条件 end; 
// 简单情景 
}
else{ 
// 在将问题转换为子问题的每一步,解决该步中剩余部分的问题 solve; 
// 递去 recursion(小规模); // 递到最深处后,不断地归来 } 
}

模型二 :在归来的过程中解决问题

function recursion(大规模){ 
if (end_condition){ 
// 明确的递归终止条件 end;
// 简单情景 
}
else{ 
// 先将问题全部描述展开,再由尽头“返回”依次解决每步中剩余部分的问题 recursion(小规模); 
// 递去 solve; 
// 归来
} }

递归一般应用场景

  1. 问题的定义是按递归定义的(例如:Fibonacci函数,阶乘);
  2. 问题的解法是递归的(例如,汉诺塔问题);
  3. 数据结构是递归的(例如:链表、树等的操作);

递归经典案例

求1-100的阶乘/和

//阶乘
function factorialize(n) {
  if (n == 1) //递归终止条件
      return 1; //简单情景
  return factorialize(n - 1) * n; //相同重复逻辑,缩小问题的规模
}
//和
function factorialize(n) {
  if (n == 1) return 1;
  return factorialize(n - 1) + n;
}

斐波拉契数列

  • 1,1,2,3,5,8,13,21···
  • 在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)
/**
 * @description 经典递归法求解
 *
 * 斐波那契数列如下:
 *
 * 1,1,2,3,5,8,13,21,34,...
 *
 * 那么计算fib(5)时,需要计算1次fib(4),2次fib(3),3次fib(2),调用了2次fib(1),即
 *
 * fib(5) = fib(4) + fib(3)
 *
 * fib(4) = fib(3) + fib(2); fib(3) = fib(2) + fib(1)
 *
 * fib(3) = fib(2) + fib(1)
 */
function fibonacci(n) {
  if (n === 1 || n === 2)  //递归终止条件
      return 1; //简单情景
  return fibonacci(n - 1) + fibonacci(n - 2); //相同重复逻辑,缩小问题的规模
}

爬楼梯

假如楼梯有 n 个台阶,每次可以走 1 个或 2 个台阶,走完这 n 个台阶有几种走法?

/**
 * 假设有1个台阶,一步直接可以走完,有1种方法
 * 假设有2个台阶,先走1步在走1步或者直接走2步,共有2种方法
 * 假设有3个台阶
 * 方式一:先走1步,还剩2个台阶,由上可得两个台阶有2种走法
 * 方式二:先走2步,还剩1个台阶,由上可得一个台阶有1种走法
 * 所以三个台阶,共有3中方法
 *
 *归纳:climbStairs(n)=climbStairs(n-1)+climbStairs(n-2)
 */
function climbStairs(n) {
  if (n === 1) return 1;
  if (n === 2) return 2;
  return climbStairs(n - 1) + climbStairs(n - 2);
}

🧨汉诺塔

Title: 汉诺塔问题

Description:古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上。

有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,

小盘在上。在移动过程中可以利用B座。要求输入层数,运算后输出每步是如何移动的。

请添加图片描述

/**1个盘子:1号盘A->C  sum = 1
 * 2个盘子:
 * 第一次:1号盘 A -> B
 * 第二次:2号盘 A -> C
 * 第三次:1号盘 B -> C  sum = 3
 * 3个盘子:
 * 第一次:1号盘A->C
 * 第二次:2号盘A->B
 * 第三次:1号盘C->B
 * 第四次:3号盘A->C
 * 第五次:1号盘B->A
 * 第六次:2号盘B->C
 * 第七次:1号盘A->C  sum = 7
 * 归纳:移动次数为:2^n-1
 *
 * 把一堆圆盘从一个柱子移动另一根柱子,必要时使用辅助的柱子。可以把它分为三个子问题:
 * 首先,移动一对圆盘中较小的圆盘到辅助柱子上,从而露出下面较大的圆盘,
 * 其次,移动下面的圆盘到目标柱子上
 * 最后,将刚才较小的圆盘从辅助柱子上在移动到目标柱子上
 * 把三个步骤转化为简单数学问题:
 * 1.把n-1个盘子由A移到 B;
 * 2.把第n个盘子由 A移到 C;
 * 3.把n-1个盘子由B 移到 C;
 */
function HanoiTower(n, a, b, c) {
  if (n == 1) {
    console.log(a + "->" + c);
  } else {
    // 将n-1个盘子借助c从a移动到b
    HanoiTower(n - 1, a, c, b);
    console.log(a + "->" + b);
    // 将n-1个盘子借助a从b移动到c
    HanoiTower(n - 1, b, a, c);
  }
}
HanoiTower(3, "A", "B", "C");

🎊二叉树的遍历

function getTreeDepth(tree) {
  // 树为空
  if (tree == null)
    // 递归终止条件
    return 0;

  let left = getTreeDepth(tree.left); // 递归求左子树深度,缩小问题的规模
  let right = getTreeDepth(tree.left); // 递归求右子树深度,缩小问题的规模

  return left > right ? left + 1 : right + 1;
}

💞总结💞

希望我的文章能对你学习递归算法有所帮助!

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

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

相关文章

​力扣解法汇总1026. 节点与其祖先之间的最大差值

目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值…

05、SpringBoot开发实用篇

一、热部署什么是热部署?简单说就是你程序改了,现在要重新启动服务器,嫌麻烦?不用重启,服务器会自己悄悄的把更新后的程序给重新加载一遍,这就是热部署。热部署的功能是如何实现的呢?这就要分两…

【技术】封装自己的 Maven Archetype Maven 原型

封装自己的 Maven Archetype Maven 原型 为什么要封装 Maven Archetype?如何封装 Maven Archetype?核心步骤具体步骤构建项目构建原型 archetypeIDEA 导入自定义原型 如何删除自定义的 Maven Archetype ? 为什么要封装 Maven Archetype? 用…

尚融宝19-Nuxt.js入门

目录 一、搜索引擎优化 1、什么是SEO 2、搜索引擎工作流程 二、服务端渲染和客户端渲染 1、什么是服务端渲染 2、什么是客户端渲染 3、两种方式各有什么优缺点? 三、Nuxt.js 1、Nuxt.js介绍 2、Nuxt.js服务器端渲染 四、安装和运行 五、页面、导航和路…

倒计时 1 天!IoTDB X EMQ 智能汽车主题 Meetup 明日不见不散!

期待已久的智能汽车主题 Meetup 活动明日即将举办!天谋科技联手 EMQ、通过数据基础设施平台的实践经验分享,共同为行业用户带来可靠高效的智能制造、智慧车联数据解决方案,快来预约直播,不要错过这场干货满满的智能汽车主题 Meetu…

类中自定义函数并调用and使用钩子函数打印类中变量

在一个类中自定义一个函数A,并在前向传播函数forword中调用这个函数 假设您正在编写一个PyTorch模型,您可以按照以下方式在类中定义函数A,并在forward函数中调用它: import torch import torch.nn as nnclass MyModel(nn.Module)…

Android修行手册 - Android Studio提升性能效率

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例 👉关于作者 众所周知,人生是一个漫长的流程,不断克服困难,不断…

【Linux】NanoPi-NEO2外接spi-lcd

这是目录一、显示接口1.1、LCD接口1.2、核心板接口二、添加驱动2.1、确认驱动型号2.2、添加驱动三、测试四、附加4.1、交叉编译器安装4.2、内核和module编译4.3、扩展rootfs大小本文使用环境: 电脑:Ubuntu 18.04.5 LTS 开发板:NanoPi-NEO2 50…

这款知名开车软件,居然暗藏大量病毒

想必大家见多了网上有关 Windows 系统宝藏神级软件的种种推荐。 其中有这么一款软件一直占据推荐榜单前列,并且坐拥无数好评。 它就是在 Steam 上售价仅 19 元,表面看起来平平无奇的 Wallpaper Engine (壁纸引擎)。 别看它价格不…

常见分布式锁4:zookeeper 瞬时znode节点 + watcher监听机制,ChatGPT回复的解决死锁的方案

原文地址在这里 临时节点具备数据自动删除的功能。当client与ZooKeeper连接和session断掉时,相应的临时节点就会被删除。zk有瞬时和持久节点,瞬时节点不可以有子节点。会话结束之后瞬时节点就会消失,基于zk的瞬时有序节点实现分布式锁&#x…

windows 环境下安装ITOP

该文章修改自旧版本的教程,如有侵权或其他问题请及时联系 windows 环境下安装ITOP 1、安装环境的下载 安装的相关文件列表,自用的程序安装包是版本3.0.2-1,环境是3.2.6版本;也可以直接通过下面链接找到最新的版本进行下载 1.1…

GitLab与jekins结合构建持续集成(cl)环境(2)

目录 GItlab配置邮箱 绑定邮箱 创建群组 添加人员 创建一个项目 添加文件 新建分支 如何拉取代码 Git bash 演示 Git GUI演示 安装jenkins 更改插件镜像源 配置jenkins使用gitlab更新代码 安装jekins插件 配置jenkins免密拉取gatlab代码 jenkins创建项目 将代码…

一种vivado联合vcs仿真以及verdi查看波形的方法

上一篇中提到vivado仿真xilinx官方的axi vip耗时过长、且每次缩放波形时加载慢的问题。后来用了正点原子的AXI DDR例程,将AXI DDR换成了AXI RAM进行读写测试,用以学习了解AXI的工作方式。详见此文读写AXI4接口RAM的简单示例_给米PHY的博客-CSDN博客。 在…

力扣题库刷题笔记20-有效的括号

1、题目如下: 2、个人Python代码实现如下: 第一次读题就理解错了题意,以为是只判断小括号闭合,大括号、中括号只是干扰元素。再次读题后,代码实现如下: 以上代码仍旧是没有理解清楚题意,以为是只…

Linux Shell 实现一键部署二进制docker+docker_compose

docker 前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。 d…

协议篇之以太网UDP协议

协议篇之以太网UDP协议一、写在前面二、TCP/IP协议分层三、UDP协议数据报格式2.1 MAC层/物理层:2.2 IP层/网络层:2.3 UDP层/传输层:2.4 应用层:四、总结四、写在后面一、写在前面 TCP/IP协议是指一个协议簇,可以理解为…

测试包的更新

有的项目有配了ci自动打包更新,开发有权限,就不用测试更新;有的是在阿里云上,测试没有权限,也是开发更新;测试自己的测试服务器,部分开发没有上传下载的权限,所以需要测试来进行更新…

CentOS 8自动化安装MongoDB并安装和实验master-slave集群、副本集群(Replica Set)、分片集群(Sharding)

文章目录CentOS 8自动化安装MongoDB安装Master-Slave集群安装并测试副本集(Replica Set)集群安装副本集(Replica Set)集群实验测试安装并测试分片集群(Sharding)注意实验使用的是ARM架构的CentOS 8 虚拟机 CentOS 8自动化安装MongoDB 首先,更…

分布式事务-概念-实现方式

分布式事务 文章目录分布式事务一、分布式事务相关概念1.分布式事务架构图2.理解本地事务相关概念3.理解分布式事务相关概念1.CAP理论2.刚性事务(CP)与柔性事务(AP)3.基于AP模型衍生下的BASE理论4 .如何从大方向选择分布式事务&am…

MySQL正则表达式 | 事务详解

目录 一、正则表达式 实例操作 二、事务 事务控制语句 MYSQL 事务处理主要有两种方法 SQL测试代码 PHP中使用事务实例 使用保留点 SAVEPOINT 一、正则表达式 MySQL可以通过 LIKE ...% 来进行模糊匹配。 MySQL 同样也支持其他正则表达式的匹配, MySQL中使用…