递归算法专题——真正理解递归和正确使用递归力扣实战应用

news2024/11/14 6:18:53

目录

1、使用递归

1.1 如何理解递归

1.2 如何写好一个递归算法

2、 算法应用【leetcode】

2.1 题一:汉诺塔问题【面试题】

 2.1.1 算法原理

 2.1.2 算法代码

2.2 题二:合并两个有序链表

2.2.1 算法原理

2.2.2 算法代码 

2.3 题三:反转链表

2.3.1 算法原理

2.3.2 算法代码

 2.4 题四:两两交换链表中的节点

2.4.1 算法原理 

2.4.2 算法代码

2.5 题五:Pow(x,n)

2.5.1 算法原理

2.5.2 算法代码


1、使用递归

1.1 如何理解递归

大家都知道,递归其实就是自己调用自己。

但是,为什么要使用递归呢?换句话说,为什么要自己调用自己呢?我们应该在什么情况下使用递归呢?又如何才能写好一个递归呢?

为什么使用递归,其实就是一个主问题中包含了相同问题的子问题,而子问题又包含了相同问题的子问题,即:出现了重复的子问题进而我们只需要将焦点放在这个重复的子问题上,使用一个相同的方案来解决整个主问题,这就是使用递归的原因。

在理解递归后,要想得心应手的使用递归算法解题,我们必须以宏观的角度看待递归:

  1. 不要在意递归的细节展开图(因为我们知道,展开图一定是正确的)
  2. 将递归函数当成一个黑盒
  3. 无条件相信这个黑盒一定能完成任务,一定能给我们带来想要的结果

1.2 如何写好一个递归算法

一个递归中,有三个要素是必不可少的:1.函数头 2.函数体 3.函数出口(回退条件)

所以要想写好递归算法,那必须清楚的知道这三个要素该如何正确设计与书写:

  1. 找到重复的子问题 --> 函数头的设计
  2. 只关心其中一个子问题是如何解决的 --> 函数体的书写
  3. 注意递归函数的出口

 虽然以上均为口头理论知识,但却尤为重要,当我们能够以宏观角度看待递归时,那递归的书写和使用将会非常得心应手。


2、 算法应用【leetcode】

2.1 题一:汉诺塔问题【面试题】

. - 力扣(LeetCode)

2.1.1 算法原理

通过画图可以发现,移动盘子的过程其实就是一个重复的子问题,因此我们使用递归求解。

【注意:一定要以宏观角度看待递归,相信这个递归函数一定能够完成任务,不要在意细节展开图,否则做题会很费劲】

  • 1.重复子问题 -> 函数头

将x柱子上的一些盘子,借助y柱子,转移到z柱子上: dfs(x,y,z, n);

  • 2.只关注重复子问题中的其中一个子问题 -> 函数体 

①现将x柱子上的n-1个盘子借助c盘转移到y柱子上,②再将x柱子上最后一个盘子转移到z柱子上,③最后再将y柱子上的n-1个盘子借助x柱子转移到z柱子上:①dfs(x, z, y, n-1); ②x.back()-> z;③dfs(y,x,z,n-1);

  • 3.函数出口

n==1时,x.back() 转移到z柱子上;

 2.1.2 算法代码

class Solution {
    public void hanota(List<Integer> a, List<Integer> b, List<Integer> c) {
        dfs(a, b, c, a.size());
    }
    public void dfs(List<Integer> a, List<Integer> b, List<Integer> c, int n) {
        if(n == 1) {
            //注意
            //递归到最深处才会移动盘子
            //移动的应该是柱子最上面的一个盘子
            c.add(a.remove(a.size() - 1));
            return;
        }
        dfs(a, c, b, n - 1);
        //同上,在递归最深处,移动的是最上面的一个盘子
        c.add(a.remove(a.size() - 1));
        dfs(b, a, c, n - 1);
    }
}

2.2 题二:合并两个有序链表

. - 力扣(LeetCode)

2.2.1 算法原理

为什么可以使用递归?选出值最小的节点,接着合并剩下的链表和另外一个链表;再选出值次小的节点,接着合并剩下的链表和另外一个链表;......依然是重复的子问题,可以递归求解。

同样,站在宏观角度看待递归。

  1. 先选出值最小节点,接着让这个递归函数合并剩下的链表并返回合并后的头结点,(我不管它怎么做到的,相信它一定可以做到)
  2. 接着,将最小的节点和返回后的(合并好的)链表相连接
  3. 返回头结点
  4. 函数出口:当为节点不存在时(node == null),说明不需要合并,为函数出口,递归回退

2.2.2 算法代码 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1 == null) return list2;
        if(list2 == null) return list1;

        if(list1.val < list2.val) {
            list1.next = mergeTwoLists(list1.next, list2);
            return list1;
        }else {
            list2.next = mergeTwoLists(list1, list2.next);
            return list2;
        }
    }
}

2.3 题三:反转链表

 . - 力扣(LeetCode)

2.3.1 算法原理

  1. 让递归函数反转链表(宏观角度,相信它一定可以完成)
  2. 并且递归函数返回反转链表后的头结点
  3. 修改当前节点与反转后链表的指向

2.3.2 算法代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) return head;

        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;

        return newHead;
    }
}

 2.4 题四:两两交换链表中的节点

. - 力扣(LeetCode)

2.4.1 算法原理 

  1. 宏观角度,先把前两个节点看做整体
  2. 使用递归函数两两交换这两个节点后的节点,并返回交换后链表的头结点
  3. 再反转前两个节点并且修改链表的指向关系
  4. 当节点为空或者只有一个节点时,为函数出口

 

2.4.2 算法代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null) return head;

        ListNode tmp = swapPairs(head.next.next);
        ListNode newHead = head.next;
        newHead.next = head;
        head.next = tmp;

        return newHead;
    }
}

2.5 题五:Pow(x,n)

. - 力扣(LeetCode)

2.5.1 算法原理

这里再次强调一下:一定要以宏观的角度看待递归!!!把递归函数当做一个黑盒,相信这个黑盒一定能够完成相关任务!

 一个数的n次方,就是这个数的n/2次方* 这个数的n/2次方;

一个数的n/2次方,就是这个数的n/4次方* 这个数的n/4次方;

一个数的n/4次方,就是这个数的n/8次方* 这个数的n/8次方;

.........

一个数的0次方,就是1;

综上所示,出现了重复的子问题,我们可以使用递归算法解题。

  1. 站在宏观角度,要得到当前数的n次方,就要得到其n/2次方(tmp),而tmp*tmp就是当前数的n次方
  2. 而递归函数就要为我们返回数的n/2次方(tmp),我们要无条件相信它。tmp = pow(x, n/2);
  3. 在n==1的函数当中,要得到0次方(n/2=0)时的数值,任何数的0次方为1,此时为函数出口,返回1
  4. 当n/2不能整除时,返回tmp*tmp*x即可
  5. 注意n为负数的情况,当成正数计算,最终返回其倒数即可

2.5.2 算法代码

class Solution {
    public double myPow(double x, int n) {
        return n < 0 ? 1 / pow(x, -n) : pow(x, n);
    }
    public double pow(double x, int n) {
        if(n == 0) return 1;

        //宏观角度看待递归,得到当前数n/2幂的值
        double tmp = pow(x, n / 2);
        
        return (n % 2 == 0) ? tmp * tmp : tmp * tmp * x;
    }
}

END

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

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

相关文章

XC企业建站系统V1.2.5

多模板主题的企业官网建站系统。提供全部无加密源码&#xff0c;支持私有化部署。 V1.2.5添加小功能 站点配置&#xff0c;增加【留言板显示开关】 站点主题 - 扩展配置&#xff0c;增加对首页【产品中心】【新闻资讯】板块的显示开关和标题自定义功能&#xff08;注&#xff…

day-49 使数组中所有元素相等的最小操作数

思路 第一个数和最后一个数要变为一致&#xff0c;需要操作n-1次&#xff0c;然后第二个数和倒数第二个数要操作n-3次 解题过程 以此类推即可得出答案 Code class Solution {public int minOperations(int n) {int ans0;int t(n-1);while(t>0){anst;t-2;}return ans;} }作…

一、selenium自动化简介selenium工具集

文章目录 一、简介二、组成部分三、selenium工具集3.1 Selenium IDE3.2 Selenium WebDriver3.3 Selenium Grid3.4 Appium 一、简介 官方网站 Selenium 是支持 web 浏览器自动化的一系列工具和库的综合项目。 它提供了扩展来模拟用户与浏览器的交互&#xff0c;用于扩展浏览器分…

企业分享 - 益丰大药房监控升级之路

益丰大药房是全国大型药品零售连锁企业&#xff08;中国沪市主板上市连锁药房&#xff09;&#xff0c;专注医药零售行业23载&#xff0c; 市值稳居国内上市连锁药店前列/中国上市公司500强。 益丰有体量庞大的研发运维团队&#xff0c;有体量庞大的 IT 设施和服务&#xff0c;…

iic学习

iic 时钟scl为高的时候 sda数据为低的时候是起始位 当scl信号为高电平的时候 sda数据为高的时候是 停止位 &#xff08;时钟稳定 数据变化 才会发生起始位和停止位&#xff09; 当sclk为高电平时 sda 数据需要保持或者需要保持稳定 &#xff08;理解就是不要有上升沿和下降沿的…

WebTopo 组态软件+ARM 工业计算机:重塑污水处理

污水处理领域也在不断寻求更高效、更稳定的解决方案。WebTopo 组态软件与 ARM 工业计算机的结合&#xff0c;尤其是 ARMxy 工业树莓派在污水处理中的应用&#xff0c;为这个领域带来了全新的变革。 WebTopo 组态软件以其清晰的布局和强大的功能&#xff0c;成为了污水处理系统中…

用C语言生成字符贪吃蛇游戏

用C语言生成字符贪吃蛇游戏 1. 引言 贪吃蛇是一个经典的小游戏&#xff0c;玩家通过控制蛇的移动来吃食物&#xff0c;随着食物的增加&#xff0c;蛇的长度也会增加&#xff0c;游戏的难度逐渐提升。本文将介绍如何使用C语言来实现一个简单的字符贪吃蛇游戏。 2. 环境准备 在…

shell介绍

[基础入门]正向shell和反弹shell-CSDN博客 shell&#xff1a;执行用户命令的接口&#xff0c;通过这个接口实现对计算机的控制 反弹shell&#xff1a;一台主机控制另一台 正向shell&#xff1a;在攻击机上开启一个监听端口&#xff0c;让被攻击机主动连接攻击机&#xff0c;…

Python实践:多种方式实现数字前补零

更多内容 个人网站&#xff1a;孔乙己大叔 一、理解数字前补零的重要性 数字前补零&#xff0c;简而言之&#xff0c;就是在数字转换为字符串时&#xff0c;在其前面填充一定数量的零&#xff0c;以达到指定的宽度。这一操作看似简单&#xff0c;实则对于数据的格式化、排序和…

基于PLC的粮食自动烘干机控制系统设计

基于PLC的粮食自动烘干机控制系统设计是一个综合性的工程任务,旨在通过PLC(可编程逻辑控制器)实现对粮食烘干过程的自动化控制,以提高烘干效率、保证烘干质量并降低能耗。以下是一个基于PLC的粮食自动烘干机控制系统设计的基本框架和关键要点: 前言 在我国,作为农业大国…

鸿蒙(API 12 Beta6版)图形【NativeImage开发指导 (C/C++)】方舟2D图形服务

场景介绍 NativeImage是提供Surface关联OpenGL外部纹理的模块&#xff0c;表示图形队列的消费者端。开发者可以通过NativeImage接口接收和使用Buffer&#xff0c;并将Buffer关联输出到OpenGL外部纹理。 针对NativeImage&#xff0c;常见的开发场景如下&#xff1a; 通过Nati…

服务器文件权限限制写入

1、先查看文件需要的用户权限。 ls -l2、判断自己的账户不具备写入权限 container里面建的文件&#xff0c;需要用户身份是root&#xff0c;如果你不在rootfile里file的话&#xff0c;是无法对需要root权限的文件增删改的。 3、创建container与宿主机共享的文件夹 如果想宿…

【Python】统计列表出现某个数字/字段的次数+去除列表的nan值+计算列表中的正负值百分比和绝对值

1. 统计一个列表出现某个数字或者字段的次数 A. 列表推导式法 原理&#xff1a;使用列表推导式找出所有等于0的元素&#xff0c;并用sum()函数计算它们的数量。 这个方法的优点是&#xff1a;可以筛选等于和不等于的&#xff0c;用来统计占比。如果需要筛选的是字符串&#…

【AQS源码】深入理解AQS的工作原理

【AQS源码】深入理解AQS的工作原理-CSDN博客

XXL-JOB分布式任务调度教程(持续更新~)

先大致声明一下流程&#xff08;具体细节在下面哦~&#xff09; 步骤&#xff1a; 1.下载xxl-job并配置以及启动 2.导入对应maven坐标 3.配置对应的配置文件以及编写对应的配置类config 4.编写要触发的方法并且给方法打上XXlJob("")注解 5.设置xxl-Job平台上的任务 …

环球佳酿:如何利用CRM系统实现营销管理数字化转型

在科技迅猛发展的今天&#xff0c;传统行业正在以空前的速度与数字技术相融合。面对从增量扩张转向存量竞争的白酒产业&#xff0c;培育新质生产力、推进数字化与智能化转型已成为业界的普遍共识。众多白酒企业纷纷探索数字化转型之路&#xff0c;力图通过创新和突破来提升竞争…

火狐浏览器设置秘籍:让https协议下的ws不加密时运行无阻(WebSocket connection HTTPS)

Uncaught (in promise) DOMException: Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. 明确指出了一个常见的安全限制&#xff1a;当尝试从一个通过HTTPS加载的页面上发起一个不安全的&#xff08…

零基础国产GD32单片机编程入门(十三)单片机IAP(在应用编程)详解及实战源码

文章目录 一.概要二.GD32F103C8T6单片机IAP介绍1.GD32F103C8T6单片机IAP基本原理2.GD32F103C8T6单片机IAP基本流程 三.配置一个BOOT工程四.配置一个APP工程五.工程源代码下载六.小结 一.概要 GD32单片机程序升级方法有很多种&#xff0c;主要有以下几种&#xff1a; 1.将编译…

【unity知识】Animator动画状态的基本属性介绍

文章目录 动画状态的基本属性1、标签Tag2、Motion 该状态所管理的动画片段3、speed 动画的播放速度4、Motion Time 播放动画片段定在一个特定时间点5、Mirror镜像动画6、CycleOffset动画偏移7、FootIK8、Write Defaults 参考完结 动画状态的基本属性 1、标签Tag 通过打标签我们…

NIO笔记04-网络编程

文章目录 1 非阻塞 vs 阻塞 ★★★阻塞非阻塞多路复用 2 Selector创建绑定 Channel 事件监听 Channel 事件&#x1f4a1; select 何时不阻塞 3 处理 accept 事件&#x1f4a1; 事件发生后能否不处理 4 处理 read 事件处理添加区分事件类型&#xff0c;客户端发送数据时会报空指…