【刷题】初探递归算法 —— 消除恐惧

在这里插入图片描述

送给大家一句话:
有两种东西,
我对它们的思考越是深沉和持久,
它们在我心灵中唤起的惊奇和敬畏就会日新月异,
不断增长,
这就是我头上的星空和心中的道德定律。
-- 康德 《实践理性批判》

初探递归算法

  • 1 递归算法
  • 2 Leetcode 面试题 08.06. 汉诺塔问题
    • 题目描述
    • 算法思路
  • 3 Leetcode 21. 合并两个有序链表
    • 题目描述
    • 算法思路
  • 4 Leetcode 206. 反转链表
    • 题目描述
    • 算法思路
  • 5 Leetcode 24. 两两交换链表中的节点
    • 题目描述:
    • 算法思路
  • 6 Leetcode 50. Pow(x, n)
    • 题目描述
    • 算法思路
  • 7 总结
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 递归算法

在解决一个规模为 n 的问题时,如果满足以下条件,我们可以使用递归来解决:

  1. 问题可以被划分为规模更小的子问题,并且这些子问题具有与原问题相同的解决方法。
  2. 当我们知道规模更小的子问题(规模为 n-1)的解时,我们可以直接计算出规模为 n 的问题的解。
  3. 存在一种简单情况,或者说当问题的规模足够小时,我们可以直接求解问题。这里一般成为函数出口(非常重要)

一般的递归求解过程如下:

  1. 验证是否满足简单情况
    简单情况是指问题规模非常小,通常可以直接得到答案的情况。我们需要首先检查当前问题是否满足这种情况。

  2. 假设较小规模的问题已经解决,解决当前问题
    在递归中,我们假设已经解决了规模较小的子问题,然后基于这些子问题的解来构建当前问题的解。这种假设称为“递归假设”。

总结来说,递归代码的编写如同使用一个“黑盒”一样,我们需要相信递归调用会正确解决子问题,而我们只需要关注处理当前的问题。

下面我们通过一个具体实例来展示如何在实践中解决问题:

假设我们要计算斐波那契数列中的第 n 项。斐波那契数列的定义如下:
F ( 0 ) = 0 \text{F}(0) = 0 F(0)=0
F ( 1 ) = 1 \text{F}(1) = 1 F(1)=1
对于 n ≥ 2 n \geq 2 n2 F ( n ) = F ( n − 1 ) + F ( n − 2 ) \text{F}(n) = \text{F}(n-1) + \text{F}(n-2) F(n)=F(n1)+F(n2)

在这个问题中:
简单情况是 F ( 0 ) \text{F}(0) F(0) F ( 1 ) \text{F}(1) F(1),我们可以直接得到答案。
对于其他情况,我们假设 F ( n − 1 ) \text{F}(n-1) F(n1) F ( n − 2 ) \text{F}(n-2) F(n2) 已经计算出来,然后通过 F ( n ) = F ( n − 1 ) + F ( n − 2 ) \text{F}(n) = \text{F}(n-1) + \text{F}(n-2) F(n)=F(n1)+F(n2) 计算出 F ( n ) \text{F}(n) F(n)

这种递归解决问题的方法非常强大,但也需要注意避免过度递归带来的性能问题,比如栈溢出或时间复杂度过高等。

接下来我们一起来解决问题吧!!!

2 Leetcode 面试题 08.06. 汉诺塔问题

上连接: 面试题 08.06. 汉诺塔问题

题目描述

在这里插入图片描述
汉诺塔是个非常有意思的问题,其典故更是神乎其神:

法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

题目给我们了xyz三个容器模拟柱子,我们需要模拟实现移动的过程,将X容器中的盘子移动到Z中。

算法思路

乍一看我们想不到什么思路,所以我们先来画图分析一波:
在这里插入图片描述

通过这三种情况我们就能分析出来,这道题可以被拆分成许多子问题来解决:

如果想要移动n个盘子

  1. 先把 n - 1 个盘子移到中转柱子上,再把第n个移到目标柱子上。
  2. 接下来处理 这n - 1 个盘子,把 n - 2 个小盘子移到中转柱子上,第 n - 1个移动到目标柱子上。
  3. 重复 1 2 直到解决问题…

注意

    // x 为当前柱子 y 为中转柱子 z 为目标柱子 
    //我们只需要注意解决当前的问题,子问题交给黑盒处理
    void dfs(vector<int>& x, vector<int>& y, vector<int>& z , int n )
    {   
        //递归出口
        if(n == 1)
        {
            int tmp = x.back();
            z.push_back(tmp);
            x.pop_back();
            return ;
        }
        //将 n 个盘子从 X 转移到 Z 
        //则先把 n-1个盘子移到 Y
        dfs(x , z , y , n - 1);
        //然后此时X只有一个最大的盘子, 移到Z
        int tmp = x.back();
        z.push_back(tmp);
        x.pop_back();
        //现在 Y 上有 n-1 个盘子继续进行移动到Z上
        dfs(y , x , z , n - 1);
        return ;
    }
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
        int n = A.size();
        dfs(A , B , C , n);
        return ;
    }

提交:过啦!!!

3 Leetcode 21. 合并两个有序链表

上连接!家人们:21. 合并两个有序链表

题目描述

在这里插入图片描述
很好理解的题目!

算法思路

相信大家看到这个题,肯定有迭代循环思路,但是今天我们通过递归来解决问题:
在这里插入图片描述

我们首先分析一下:

  • 当前问题:当我们处理当前情况时,我们需要把后续处理交给黑盒,我们需要的是将较小的节点插入到新链表中
  • 子问题:处理除去以被处理的“较小的节点”之外的链表节点,使其合并。
  • 函数出口:当我们处理到两个链表都为空时直接返回,或者一方为空直接返回另一链表即可!
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    	//处理为空的情况
        if(l1 == nullptr) return l2;
        if(l2 == nullptr) return l1;
        //都不为空,选择较小值进行插入!!!
        if(l1->val < l2->val)
        {
        	//l1 小 就把它的next交给黑盒处理
            l1->next = mergeTwoLists(l1->next , l2);
            //然后将它返回(这样黑盒才可以获取当前节点的next节点)
            return l1;
        }
        else
        {
        	//l2 小 就把它的next交给黑盒处理
            l2->next = mergeTwoLists(l1 , l2->next);
            return l2;
        }
    }

提交:过啦!!!

4 Leetcode 206. 反转链表

上链接: 206. 反转链表 !

题目描述

在这里插入图片描述
同样很好理解,接下来我们来使用递归解决问题

算法思路

首先这道题需要注意的一点是:我们要先找到新链表的头(即当前链表的尾节点)黑盒的返回值设置为新链表的头,然后再来进行反转。就类似二叉树的后序遍历。我们不能从链表的头开始反转到尾(先序遍历)。因为这样就无法获取新链表的头结点了

从宏观来看:我们只需要处当前问题:

  1. 子问题: 后续节点的反转!黑盒会返回我们的头结点。我们的黑盒一定可以帮助我们解决后序的节点的反转。
  2. 当前问题:把当前节点插入到以被反转的链表后,把当前节点的next设置为空即可!
  3. 函数出口:当走到链表结尾即为出口!
ListNode* reverseList(ListNode* head) {
        //寻找新的头结点
        if( head == nullptr || head->next == nullptr ) return head;
        ListNode* newhead = reverseList(head->next);
        //进行倒置
        head->next->next = head;
        //next设置为空
        head->next = nullptr;
		//返回新链表的头
        return newhead;
    }

提交:过啦!!!

5 Leetcode 24. 两两交换链表中的节点

跟上节奏:24. 两两交换链表中的节点 !!!

题目描述:

在这里插入图片描述
题目也很好理解奥

算法思路

我们依旧是使用递归来解决:

  1. 当前问题:置换两个节点,并指向后续以及置换完成的链表。
  2. 子问题:后序节点的置换
  3. 函数出口:为空或只有一个节点之间返回即可。
    ListNode* swapPairs(ListNode* head) {
        //利用递归解决问题
        //一次要处理两个节点
        if(head == nullptr) return nullptr;
        if(head->next == nullptr) return head;

        //继续处理 --- 相信 swapPairs(tmp) 这个会处理好剩余部分
        ListNode* tmp = swapPairs(head->next->next);
        //进行处理
        //记录下 1 2 节点的后面的2节点,它是置换后的头节点。
        ListNode* ret = head->next;
        //置换
        head->next->next = head;
        head->next = tmp;
        
        return ret;
    }

提交:过啦!!!

6 Leetcode 50. Pow(x, n)

最后一题:50. Pow(x, n) !!!

题目描述

在这里插入图片描述
这道题需要我们使用幂函数,当然不是一般的循环相乘(必然超时),我们要实现快速幂!

算法思路

快速幂的思想很简单:假如我们需要 210 ,我们就求25 ,求 25 就求 22 * 22 * 2 …以此类推直到次数为 0 就返回 1

需要注意的是负数的处理,求负次幂,我们可以先求正的然后在取倒数。
还有边界的处理,题目所给的最小值 - 231 取正后为 231,超出int的范围,所以需要转换为long long

    double myPow(double x, long long n) {
        if(n == 0) return 1;
        if( n < 0 ) 
        {
            long long t = (long long)(-n);
            double tmp = myPow( x , t / 2);
            return t % 2 == 0 ? 1 / (tmp * tmp) : 1 / (tmp * tmp * x);
        }
        else
        {
         double tmp = myPow( x ,  n / 2);
         return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
        }
      
    }

提交过啦!!!

7 总结

我们进行递归算法,只需要处理好当前问题,其余相信我们的黑盒可以解决。注意:

  1. 函数出口的设置,这个是关键!!!
  2. 返回值的设置要合适,看题分析!!!

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

前端逆向之查看接口调用栈

一、来源 再分析前端请求接口数据的时候&#xff0c;其中有一个sid不知道是前端如何获取的&#xff0c;一般情况下只需要全局搜搜sid这个字符串或者请求接口的名称就可以了&#xff0c;基本都能找到sid的来源&#xff0c;但是今天这个不一样&#xff0c;搜什么都搜不到 接口地…

SAP跨服务器传输请求号

环境一、两台服务器并没有维护连接传输线路&#xff08;DEV和QAS&#xff09; 环境二、需要将外部公司服务器上的请求号传输到内部服务器中 方式&#xff1a;先从开发环境或服务器中下载请求号&#xff0c;再将请求号上传到目标服务器或环境中&#xff0c;在目标服务器使用ST…

分享:重庆耶非凡科技有限公司人力资源项目靠不靠谱?

在当今快速变化的商业环境中&#xff0c;人力资源项目作为企业发展的重要支撑&#xff0c;其专业性和可靠性成为企业选择合作伙伴时的重要考量因素。重庆耶非凡科技有限公司作为一家在行业内颇具影响力的科技企业&#xff0c;其人力资源项目——人力RPO(招聘流程外包)项目&…

实现Redis和数据库数据同步问题(JAVA代码实现)

这里我用到了Redis当中的发布订阅模式实现(JAVA代码实现) 先看图示 下面为代码实现 首先将RedisMessageListenerContainer交给Spring管理. Configuration public class redisConfig {AutowiredRedisConnectionFactory redisConnectionFactory;AutowiredQualifier("car…

Hive安装-内嵌模式

1.官网下在hive3.1.2版本 Index of /dist/hive/hive-3.1.2 2.上传到master节点的/opt/software目录下 3.解压到/opt/module目录下 tar -zxvf apache-hive-3.1.2-bin.tar.gz -C /opt/module/ 检查解压后文件 4.修改名字 改为hive cd /opt/module mv apache-hive-3.1.2-bin…

数据结构 实验 1

题目一&#xff1a;用线性表实现文具店的货品管理问题 问题描述&#xff1a;在文具店的日常经营过程中&#xff0c;存在对各种文具的管理问题。当库存文具不足或缺货时&#xff0c;需要进货。日常销售时需要出库。当盘点货物时&#xff0c;需要查询货物信息。请根据这些要求编…

Crosslink-NX器件应用连载(11): 图像(数据)远程传输

作者&#xff1a;Hello&#xff0c;Panda 大家下午好&#xff0c;晚上好。这里分享一个Lattice Crosslink-NX器件实现图像或数据&#xff08;卫星数据、雷达数据、ToF传感器数据等&#xff09;远程传输的案例&#xff08;因为所描述的内容颇杂&#xff0c;晒图不好晒&#xff…

HCIP的学习(27)

RSTP—802.1W—快速生成树协议 STP缺陷&#xff1a; 1、收敛速度慢----STP的算法是一种被动的算法&#xff0c;依赖于计时器来进行状态变化 2、链路利用率低​ RSTP向下兼容STP协议。&#xff08;STP不兼容RSTP&#xff09; 改进点1—端口角色 802.1D协议---根端口、指定端口…

[数据集][目标检测]猕猴桃检测数据集VOC+YOLO格式1838张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1838 标注数量(xml文件个数)&#xff1a;1838 标注数量(txt文件个数)&#xff1a;1838 标注…

【Java】Java遍历Map方法合集

本文摘要&#xff1a;Java遍历Map方法合集 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。公粽号&#xff1a;洲与AI。 &#x1f913; 欢迎大家关注&am…

如何进入 -MGMTDB目录

想想这个问题&#xff0c;大家可能觉得很简单吧&#xff0c;先不看答案&#xff0c;你试一试如何进去 1.问题现象&#xff1a; 我直接进入&#xff1a; cd -MGMTDB 直接就报错了&#xff1a; [gridhost03 _mgmtdb]$ cd -MGMTDB -bash: cd: -M: invalid option cd: usage: c…

deepin开机取消挂载windows系统磁盘(Win11+deepinV23RC双系统)

目录 一、需求分析二、实现方法 一、需求分析 机器有两块硬盘&#xff0c;硬盘0装的是Win11,硬盘1装的是deepinV23RC,为避免使用deepin系统时对windows分区误操作&#xff0c;因此需要取消windows分区的挂载。 二、实现方法

解决TrueNas Scale部署immich后人脸识别失败,后台模型下载异常,immich更换支持中文搜索的CLIP大模型

这个问题搞了我几天终于解决了&#xff0c;搜遍网上基本没有详细针对TrueNas Scale部署immich应用后&#xff0c;CLIP模型镜像下载超时导致人脸识别失败&#xff0c;以及更换支持中文识别的CLIP模型的博客。 分析 现象&#xff1a;TrueNas Scale安装immich官方镜像应用后&…

记录一次cnvd事件型证书漏洞挖掘

事件起因是因为要搞毕设了&#xff0c;在为这个苦恼&#xff0c;突然负责毕设的老师说得到cnvd下发的证书结合你的漏洞挖掘的过程是可以当成毕设的&#xff0c;当时又学习了一段时间的web渗透方面的知识&#xff0c;于是踏上了废寝忘食的cnvd证书漏洞挖掘的日子。 前言&#x…

动态规划算法:背包问题

背包问题概述 背包问题 (Knapsack problem) 是⼀种组合优化的 NP完全问题 。 问题可以描述为&#xff1a;给定⼀组物品&#xff0c;每种物品都有⾃⼰的重量和价格&#xff0c;在限定的总重量内&#xff0c;我们如何选择&#xff0c;才能使得物品的总价格最⾼。 根据物品的个…

vector实现后半部分

一.迭代器失效 1.定义 指原迭代器在扩容/缩容/修改后指向无效元素或无效地址处 erase的迭代器失效 2.原因&#xff1a; 1.有的编译器实现erase会缩容拷贝 2.删除最后一个后&#xff0c;其指向无效元素 VS中不允许再次使用erase完的迭代器&#xff0c;为了让编写的代码移植…

32位与64位程序下函数调用的异同——计科学习中缺失的内容

前言 今天&#xff0c;通过一个有趣的案例&#xff0c;从反编译的角度看一下C语言中函数参数是如何传递的。 创建main.c文件&#xff0c;将下面实验代码拷贝到main.c文件中。 # main.c #include <stdio.h>int test(int a, int b, int c, int d, int e, int f, int g, …

浔川python社获得全网博主原力月度排名泸州地区第二名!

今日&#xff0c;浔川python社在查看全网博主原力月度排名泸州地区时&#xff0c;一看就震惊啦&#xff01; 全网博主原力月度排名泸州地区排名榜单 全网博主原力月度排名泸州地区第二名为&#xff1a;浔川python社。 感谢粉丝们的支持&#xff01;浔川python社还会继续努力&a…

ubuntu--Linux使用

Linux使用 Linux 系统简介 linux Linux 就是一个操作系统&#xff0c;与 Windows 和 Mac OS 一样是操作系统 。 操作系统在整个计算机系统中的角色 : Linux 主要是 系统调用 和 内核 那两层。使用的操作系统还包含一些在其上运行的应用程序&#xff0c;比如vim、google、vs…

Glow模型【图解版加代码】

论文&#xff1a;Glow: Generative Flow with Invertible 1x1 Convolutions 代码&#xff1a;pytorch版本&#xff1a;rosinality/glow-pytorch: PyTorch implementation of Glow (github.com) 正版是TensorFlow版本 openai的 参考csdn文章&#xff1a;Glow-pytorch复现gith…