Offer必备算法07_递归_五道力扣题详解(由易到难)

目录

递归算法原理

①力扣面试题 08.06. 汉诺塔问题

解析代码

②力扣21. 合并两个有序链表

解析代码

③力扣206. 反转链表

解析代码

④力扣24. 两两交换链表中的节点

解析代码

⑤力扣50. Pow(x, n)

解析代码

本篇完。


递归算法原理

        递归算法个人经验:给定一个任务,相信递归函数一定能解决这个任务,根据任务所需的东西,给出函数参数,然后实现函数内容,最后找出口。

        递归算法是指在解决问题的过程中,不断地调用自身来解决子问题的一种算法。其基本思想是将原问题转化为同类更小的子问题,直到达到最小可解问题的情况,然后再将子问题的答案合并起来解决原问题。递归算法基本设计原理是分而治之,即将问题分成小问题分别解决,最终将所有小问题的答案合并成原问题的答案。

        递归算法适用于问题具有递归性质的场景。这些问题通常可以分解为一些同样类型但规模更小的子问题,递归算法可以通过递归调用来解决这些子问题,再将子问题的答案组合成原问题的答案。例如,计算斐波那契数列,求解汉诺塔问题等等都可以用递归算法来解决。

        在使用递归算法中,首先要注意递归终止条件的设置。如果没有正确的终止条件,递归算法将会无限循环,导致程序崩溃。其次,注意递归调用时的参数传递问题,要确保每次递归调用时传递的参数和问题规模正确。此外,在递归算法中,可能会出现栈溢出的问题,特别是问题规模很大的情况下,应注意算法的时间和空间复杂度,以避免因内存不足而引起的程序异常。

递归 VS 迭代(循环):

递归和迭代本质都是解决重复的子问题,所以代码可以相互转换。

递归 VS 深搜(dfs):

递归的展开图,其实就是对一颗树做一次深度优先遍历。

什么时候用递归方便,什么时候用迭代方便:

当递归展开图复杂时用递归(多叉树等),当递归展开图简单时用迭代(一条路径等)。


①力扣面试题 08.06. 汉诺塔问题

面试题 08.06. 汉诺塔问题

难度 简单

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

示例1:

 输入:A = [2, 1, 0], B = [], C = []
 输出:C = [2, 1, 0]

示例2:

 输入:A = [1, 0], B = [], C = []
 输出:C = [1, 0]

提示:

  1. A中盘子的数目不大于14个。
class Solution {
public:void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {};

解析代码

 一道递归方法的经典题目,看看图:

假设 n = 1,只有一个盘子,很简单,直接把它从 A 中拿出来,移到 C 上;

如果 n = 2 呢?这时候我们就要借助 B 了,因为小盘子必须时刻都在大盘子上面,共需要 4 步。

如果 n > 2 呢?思路和上面是一样的,我们把 n 个盘子也看成两个部分,一部分有 1 个盘子,另一部分有 n - 1 个盘子。

        在思考这个问题的时候,就将最初的 n 个盘子从 A 移到 C 的问题,转化成了将 n - 1 个盘子从 A 移到 C 的问题, 依次类推,直至转化成 1 个盘子的问题时,问题也就解决了。这就是分治的思想。

        而实现分治思想的常用方法就是递归。不难发现,如果原问题可以分解成若干个与原问题结构相同但规模较小的子问题时,往往可以用递归的方法解决。具体解决办法如下:

n = 1 时,直接把盘子从 A 移到 C;
n > 1 时,
先把上面 n - 1 个盘子从 A 移到 B(子问题,递归);
再将最大的盘子从 A 移到 C;
再将 B 上 n - 1 个盘子从 B 移到 C(子问题,递归)。

递归法:给定一个任务,相信递归一定能解决这个任务,然后找出口:

class Solution {
public:void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {dfs(A, B, C, A.size());}void dfs(vector<int>& A, vector<int>& B, vector<int>& C, int n){   // 递归:A盘 借助 B盘 转移A最上面n-1个盘 到C盘if(n == 1){C.push_back(A.back());A.pop_back();return;}dfs(A, C, B, n-1);C.push_back(A.back());A.pop_back();dfs(B, A, C, n-1);}
};

②力扣21. 合并两个有序链表

21. 合并两个有序链表

难度 简单

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {}
};

解析代码

        以前C语言用迭代(循环)写过了,递归的思路就是把小结点链接到这个小结点的下一个和另一条结点链接好的链表(递归),然后返回小的结点,出口就是有一个链表为空,返回另一个。

 

上图就是让①链接到绿色链接好的链表上。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {return  _mergeTwoLists(list1, list2);}ListNode* _mergeTwoLists(ListNode* list1, ListNode* list2){if(list1 == nullptr)return list2;if(list2 == nullptr)return list1;if(list1->val <= list2->val){list1->next = _mergeTwoLists(list1->next, list2);return list1;}else{list2->next = _mergeTwoLists(list2->next, list1);return list2;}}
};

③力扣206. 反转链表

206. 反转链表

LCR 024. 反转链表

难度 简单

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseList(ListNode* head) {}
};

解析代码

这次循环迭代也写过了,且用循环更好,但练下递归:

左图就是把紫矿里的链表反转后链接到head,head再指向空,右图就是把链表看成一棵树。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseList(ListNode* head) {// 用下面的循环迭代更好,但练下递归;// 链表看成一颗树,遇到空结点/叶子结点就返回,让叶子结点指回去if(head == nullptr || head->next == nullptr)return head;ListNode* newHead = reverseList(head->next); // 把head后面的都递归好head->next->next = head; // 让叶子结点指回去head->next = nullptr; // 为了统一步骤return newHead;/*ListNode *newHead = nullptr, *cur = head;while(cur){ListNode *curNext = cur->next;cur->next = newHead; // 头插newHead = cur; // 往后走cur = curNext;}return newHead;*/}
};

④力扣24. 两两交换链表中的节点

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

难度 中等

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100] 内
  • 0 <= Node.val <= 100
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head) {}
};

解析代码

递归是和反转链表一样的思路:

把下图紫框中链表两两交换,然后再把剩下的两个结点交换。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head == nullptr || head->next == nullptr)return head;ListNode* tmp = swapPairs(head->next->next); // 把两个结点之外的看成另一部分head->next->next = head;auto ret = head->next; // 保存一下要返回的结点head->next = tmp;return ret;}
};

⑤力扣50. Pow(x, n)

50. Pow(x, n)

难度 中等

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,x^n )。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2^-2 = 1/2^2 = 1/4 = 0.25

提示:

  • -100.0 < x < 100.0
  • -2^31 <= n <= 2^31-1
  • n 是一个整数
  • 要么 x 不为零,要么 n > 0 。
  • -10^4 <= xn <= 10^4
class Solution {
public:double myPow(double x, int n) {}
};

解析代码

循环迭代会超时,递归就是先求n/2次方,然后分情况讨论,要注意边界情况:

class Solution {
public:double myPow(double x, int n) { // long long 防-2^31变成正数溢出return n < 0 ? 1 / _myPow(x, -(long long)n) : _myPow(x, n);}double _myPow(double x, long long n){if(n == 0)return 1;double tmp = myPow(x, n / 2);return n % 2 == 0 ? tmp*tmp : tmp*tmp*x;}
};

本篇完。

下一部分是二叉树的深搜dfs。

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

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

相关文章

PHP支持的伪协议

php.ini参数设置 在php.ini里有两个重要的参数allow_url_fopen、allow_url_include。 allow_url_fopen:默认值是ON。允许url里的封装协议访问文件&#xff1b; allow_url_include:默认值是OFF。不允许包含url里的封装协议包含文件&#xff1b; 各协议的利用条件和方法 php:/…

数据结构OJ题——top-k问题:最小的K个数(Java实现)

题目链接&#xff1a;top-k问题&#xff1a;最小的K个数 top-k问题&#xff1a;最小的K个数假 1.方法一2.方法二时间复杂度 3.方法三时间复杂度 1.方法一 各种排序算法&#xff08;由于本文主要讲有关堆的使用&#xff0c;这里不做有关排序算法解决本题的介绍。对于Top-K问题…

linux(阿里云)安装pytorch

目录 环境 安装步骤 1 检查python3和pip3是否已经安装 2 安装pytorch 3 安装完毕&#xff0c;检查pytorch版本 环境 阿里云 ubuntu 22.04 UEFI版 64位 安装步骤 1 检查python3和pip3是否已经安装 输入下面两条指令&#xff1a; python3 --version pip --version 检…

1Panel使用GMSSL+Openresty实现国密/RSA单向自适应

本文 首发于 Anyeの小站&#xff0c;转载请取得作者同意。 前言 国密算法是国家商用密码算法的简称。自2012年以来&#xff0c;国家密码管理局以《中华人民共和国密码行业标准》的方式&#xff0c;陆续公布了SM2/SM3/SM4等密码算法标准及其应用规范。其中“SM”代表“商密”&a…

ChatGPT对软件测试的影响!

ChatGPT 是一个经过预训练的 AI 语言模型&#xff0c;可以通过聊天的方式回答问题&#xff0c;或者与人闲聊。它能处理的是文本类的信息&#xff0c;输出也只能是文字。它从我们输入的信息中获取上下文&#xff0c;结合它被训练的大模型&#xff0c;进行分析总结&#xff0c;给…

【C++杂货铺】string详解

目录 1. 基本概念&#xff1a; 1.1 本质&#xff1a; 1.2 string和char*区别&#xff1a; 1.3 特点&#xff1a; 2. 构造函数(初始化) 3. 赋值操作 4. 字符串拼接 5 查找 和 替换 6. 字符串比较 7. 字符存取 8. 插入和删除 ​9. 子串获取 &#x1f308;前言&#x…

Rocky Linux网卡静态配置

一、开源系统 Rocky Linux 下载安装 1、安装教程 Rocky Linux 下载安装 二、远程工具 MobaXterm下载安装 1、安装教程 MobaXterm 下载安装 三、Rocky Linux 网卡配置 1、使用ip addr确认网卡名称&#xff08;此处可得知网卡为ens160&#xff09; [rootlocalhost ~]# ip a 1:…

23款奔驰GLE350升级小柏林音响 安装效果分享

小柏林之声音响是13个喇叭1个功放&#xff0c;功率是590W&#xff0c;对应普通音响来说&#xff0c;已经是上等了。像著名的哈曼卡顿音响&#xff0c;还是丹拿音响&#xff0c;或者是BOSE音响&#xff0c;论地位&#xff0c;论音质柏林之声也是名列前茅。星骏汇小许Xjh15863 升…

2.C语言——输入输出

1.字符输入输出函数 1.输入:getchar() 字面意思&#xff0c;接收单个字符&#xff0c;使用方法 char a; a getchar();实际上效果等同于char a; scanf("%c",&a);2.输出:putchar() 2.格式化输入输出函数 1.输入:scanf() 格式&#xff1a; scanf(“格式控制…

Axes属性汇总

Axes属性很多&#xff0c;主要起控制坐标区的外观和行为的作用&#xff0c;共涉及十三类。 第1类&#xff1a;字体 Font Name——字体名称&#xff0c;默认为’Helvetica’。 要使用在任何区域设置中都有较好显示效果的等宽字体&#xff0c;请使用 “FixedWidth”。等宽字体依…

系统测试计划(直接套用实际)

1测试目的 2测试范围 3资源要求 3.1人力资源 3.2指派干系人 3.3测试环境 3.4测试工具 4测试类型 5测试安排 5.1测试进度 5.2测试策略 5.2.1测试需求 5.2.2测试类型 6测试停止标准 7测试风险 8缺陷管理 8.1缺陷属性 8.2缺陷类型 8.3缺陷严重程度 8.4缺陷优先级 8.5缺陷状态 8.6缺…

C#上位机与三菱PLC的通信07--使用第3方通讯库读写数据

1、通讯库介绍 mcprotocol 是一个基于 Node.js 的三菱 PLC MC 协议通信库&#xff0c;具有以下特点&#xff1a; 支持多种三菱 PLC MC 协议的设备&#xff0c;如 FX3U、Q03UDECPU、QJ71E71 等。 支持多种功能码和数据类型&#xff0c;如读取线圈&#xff08;M&#xff09;、…

[AIGC] 利用 chatgpt 深入理解 Java 虚拟机(JVM)

Java 虚拟机&#xff08;JVM&#xff09;是 Java 编程语言的核心运行环境&#xff0c;它负责解释和执行 Java 字节码。它是 Java 程序能够跨平台运行的关键&#xff0c;因为不同的操作系统和硬件平台都有自己的指令集和体系结构&#xff0c;而 JVM 则提供了一个统一的运行环境&…

硬核!10分钟教你搭建一个本地版GPT4.0!

今天10分钟手把手教会你在自己电脑上搭建一个官方原版的GPT4.0。 不用ChatGPT账号&#xff0c;不用API&#xff0c;直接免费使用上官方原版的GPT4.0&#xff01; 对&#xff01;你没看错&#xff01;不仅是正版GPT4.0&#xff0c;还完全免费&#xff01; 而且整个部署流程极其简…

java根据前端所要格式返回树形3级层级数据

一、业务分析&#xff0c;根据前端需求返回如下数据格式 二、后端设计数据类型VO /*** author TTc* version 1.0* date 2024/2/15 16:47*/ Data AllArgsConstructor NoArgsConstructor public class Catalog2Vo {/*** 一级父分类的 id*/private String catalog1Id;/*** 三级子…

C# 12 中新增的八大功能你都知道吗?

一、主构造函数 在 Visual Studio 2022 版本 17.6 预览版 2 中引入。 从 C# 12 开始&#xff0c;可以在类和结构中声明主构造函数。主构造函数参数都在类的整个主体的范围内。为了确保显式分配所有主构造函数参数&#xff0c;所有显式声明的构造函数都必须使用 this() 语法调用…

SSL证书要钱吗?SSL证书一定要安装吗?

为了保护网站的数据安全和用户隐私&#xff0c;越来越多的网站开始采用SSL证书来加密数据传输。那么&#xff0c;SSL证书到底是否需要收费呢&#xff1f;又是否一定要安装呢&#xff1f;本文将从专业角度为您解答这些问题。 首先&#xff0c;我们来了解一下什么是SSL证书。SSL…

CPU是如何工作的?什么是冯·诺依曼架构和哈弗架构?

《嵌入式工程师自我修养/C语言》系列——CPU是如何工作的&#xff1f;什么是冯诺依曼架构和哈弗架构&#xff1f; 一、CPU内部结构及工作原理1.1 CPU的结构1.2 CPU工作流程举例 二、计算机体系结构2.1 冯诺依曼架构2.2 哈弗架构 三、总结 快速学习嵌入式开发其他基础知识&#…

《源代码》:穿越思考的时空之旅

计算机专业必看的几部电影 计算机专业必看的几部电影&#xff0c;就像一场精彩的编程盛宴&#xff01;《黑客帝国》让你穿越虚拟世界&#xff0c;感受高科技的魅力&#xff1b;《社交网络》揭示了互联网巨头的创业之路&#xff0c;《源代码》带你穿越时间解救世界&#xff0c;…

error: src refspec main does not match any解决办法

一、问题描述&#xff1a; 用GitHub Actions自动部署Hexo&#xff0c;到了最关键的一步&#xff1b;突然报错&#xff1a;error: src refspec main does not match any 1、错误一&#xff1a; main分支应填写为master分支&#xff1b;但是只改这里也会报其他错误 2、错误二&a…