单链表的递归详解 (leetcode习题+ C++实现)

news2025/1/22 12:49:47

文章目录

  • 合并两个有序链表
  • 翻转链表
  • 链表中移除节点

合并两个有序链表

传送门:
https://leetcode.cn/problems/merge-two-sorted-lists/description/

题目要求;
给你两个有序的链表,将这两个链表按照从小到大的关系,合并两个链表为一个新的链表。

在这里插入图片描述

解:
看到两个合成一个的,我们就可以利用二路归并的思想来解决,这道题也是如此。
关于顺序表和链表的二路归并可以看我之前发表的一篇博客:
顺序表和单链表的二路归并问题


我们本节主要讨论如何利用递归来求解合并两个单链表的问题?

设计递归:

  • 递归的终止:当递归到单链表1 == nullptr,或者单链表2 == nullptr 的时候,则终止递归,并且我们可以得知,当一个链表为空时,另一个链表一定还没有遍历完,所以我们返回其对应的另一个链表。
  • 递归如何进行:我们每次比较list1与list2的节点值得大小,让较小的链表的next进入递归,并且存储递归返回的结果。

过程:以1 2 4 — 1 3 4两个链表为例子。

  1. 首先list1的值与list2的值相同,但是当list1的值大于等于list2的时候,我们都操纵list2,list2的next进入递归,此时list2指向 节点3.
  2. 比较节点1 与 节点3,list1的节点值小,所以操纵list1的next,进入递归.
  3. 一直往下递归,直到最后,list2指向了空,图中 蓝色圈5 所示。
  4. 此时,我们递归已经完成,接下来该回溯了。
  5. 节点依次回溯到上一个节点的next,例如图中的 橙色圆圈就是回溯的过程,与之对应的是蓝色圆圈的递归的过程。
  6. 一直回溯到起点,节点指针依次连接,我们就得到了一条新的链表,这个链表就是我们合并后的新链表。
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
代码示例:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if (list1==nullptr)
        {
            return list2;
        }
        if (list2==nullptr)
        {
            return list1;
        }
        //每一次找到节点值小的链表进入递归
        if (list1->val>=list2->val)
        {
            list2->next=mergeTwoLists(list1,list2->next);
            return list2;
        }
        list1->next=mergeTwoLists(list1->next,list2);
        return list1;
    }
};

翻转链表

传送门:
https://leetcode.cn/problems/reverse-linked-list/description/

题目要求:把一个单链表的所有节点原地翻转。

我们可以利用迭代来求解这个问题:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pTemp=nullptr;
        ListNode* pCur=head;
        //前一个节点置空,可以在第一步就断开链表
        ListNode* pPre=nullptr;
        while (pCur)
        {
        	//1. 保存下一个节点位置
            pTemp=pCur->next;
            //2. 当前节点指向前一个节点
            pCur->next=pPre;
            //3. 前一个节点指向当前节点
            pPre=pCur;
            //4. 继续遍历下一个节点
            pCur=pTemp;
        }
        return pPre;
    }
};

迭代的方式很简单,自己画图就可以理解,重点要理解第二步与第三步


接下来我们看递归:

设定一个pNew节点为我们的结果,最后返回pNew即可。

递去: 当节点为空或者next为空时,返回此节点,

  1. 回溯第一步:pNew节点指向5,此时已经回溯次了,所以head指向4,head的next的next等于head,即让pNew的节点5连接节点4;head->next为空,即让前一个head节点4断开,后一个head节点4指向空。形成了 5 -> 4 -> NULL
    在这里插入图片描述

  1. 回溯第二步:pNew节点还是指向5,此时是回溯的第次,所以head指向3,注意head的位置,相当于head第一步逆转的节点5同时指向节点4,head的next的next等于head,即让pNew的节点4连接节点3;head->next为空,即让前一个head节点3断开,后一个head节点3指向空。形成了 5 -> 4 -> 3 -> NULL
    在这里插入图片描述

  1. 回溯第三步:pNew节点还是指向5,此时是回溯的第次,所以head指向2,注意head的位置,相当于head第二步逆转的节点4同时指向节点3,head的next的next等于head,即让pNew的节点3连接节点2;head->next为空,即让前一个head节点2断开,后一个head节点2指向空。形成了 5 -> 4 -> 3 -> 2 -> NULL

在这里插入图片描述

  1. 最后一步也是如此,把节点一连接到按同样的操作连接到链表的末尾。

代码如下:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head==nullptr || head->next==nullptr)
        {
            return head;
        }
        ListNode* pNew=reverseList(head->next);
        head->next->next=head;
        head->next=nullptr;
        return pNew;
    }
};

链表中移除节点

传送门:
https://leetcode.cn/problems/remove-nodes-from-linked-list/

题目要求:

给你一个链表的头节点 head 。
对于列表中的每个节点 node ,如果其右侧存在一个具有 严格更大 值的节点,则移除 node 。
返回修改后链表的头节点 head 。

在这里插入图片描述

这道题利用非递归可以更加有效,非递归的空间复杂度是O(1),利用非递归可以首先将链表逆转,然后依次遍历每个节点,删除,最后再翻转回来。这里不再多说。


递归过程:

在这里插入图片描述


class Solution {
public:
    ListNode* removeNodes(ListNode* head) {
        if (head==nullptr || head->next==nullptr)
        {
            return head;
        }
        ListNode* pNew=removeNodes(head->next);
        if (pNew->val>head->val)
        {
            return pNew;
        }
        head->next=pNew;
        return head;
    }
};

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

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

相关文章

Mybatis快速入门

Mybatis安装与配置 Mybatis概述 Mybatis本质上是一个别人写好的框架,用于简化 JDBC 开发,通过Mybatis框架,可以极大的降低JDBC的开发难度。 官方文档:https://mybatis.org/mybatis-3/zh/index.html Mybatis快速入门 需求&…

MySQL进阶实战10,MySQL全文索引

一、全文索引 全文索引的目的是 通过关键字的匹配进行查询过滤,基于相似度的查询,而不是精确查询。 全文索引利用分词技术分析出文字中某关键字的频率和重要性,并按照一定的算法智能的筛选出我们想要的结果。 全文索引一般用于字符串中某关…

tomcat服务器安装及配置教程(保姆级教程)

Tomcat安装教程 (以tomcat-9.0.62为例:) 1.下载安装包 可以从官网下载安装包: (1)从官网下载 输入网址进入官网 选择版本10,版本9,或者版本8,都可以,这里…

掘金热榜首推!阿里内部都在用的Java后端面试笔记,囊括99%的主流技术

纵观今年的技术招聘市场, Java依旧是当仁不让的霸主 !即便遭受 Go等新兴语言不断冲击,依旧岿然不动。究其原因: Java有着极其成熟的生态,这个不用我多说;Java在 运维、可观测性、可监 控性方面都有着非常优…

Spring Boot JPA 本机查询示例

在本教程中,您将了解如何在 Spring 引导中使用 Spring Data JPA 本机查询示例(带参数)。我将向您展示: 将 Spring JPA 本机查询与Query注释一起使用的方法如何在 Spring 引导中执行 SQL 查询具有 WHERE 条件的 JPA 选择查询示例 …

动态SQL

动态SQL 可以根据具体的参数条件,来对SQL语句进行动态拼接。比如在以前的开发中,由于不确定查询参数是否存在,许多人会使用类似于where 1 1 来作为前缀,然后后面用AND 拼接要查询的参数,这样,就算要查询的…

MongoShake数据灾备与迁移

安装部署 解压 建议部署在离目标端近的地方,比如部署再目标端本地 tar -zxvf mongo-shake-v2.8.1.tgz配置 同构环境下主要参数 启动 执行下述命令启动同步任务,并打印日志信息,-verbose 0表示将日志打印到文件,在后台运行 …

【Linux从入门到放弃】Linux基本指令大全

🧑‍💻作者: 情话0.0 📝专栏:《Linux从入门到放弃》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢! L…

黑苹果之微星(MSI)主板BIOS详细设置篇

很多童鞋安装黑苹果的时候会卡住,大部分原因是cfg lock 没有关闭,以及USB端口或SATA模式设置错误。 为了避免这些安装阶段报错的情况发生,今天给大家分享一下超详细的BIOS防踩坑设置指南--微星(MSI)主板BIOS篇&#xf…

springcloud总结篇

一.整体结构 springcloud总体架构 对比学习 二.具体 1.场景模拟 订单服务调用库存服务来更新数据库中的库存 2.springcloud问题解析 Eureka OpenFeign (RibbonRestTemplate) Hystrix Gateway config Bus 订单服务只知道库存服务的名称…

Python测试-unittest,2022-11-27

(2022.11.27 Sun) unittest是Python自带的单元测试框架。unittesthtml和pytestallure(测试报告)成为常用的自动测试和报告的框架组合。 unittest-archi-2022-11-23-2114.png 概念 test case测试用例:测试用例是测试的基本单元,用于测试一组特定输入的特…

OpenCV图像特征提取学习四,SIFT特征检测算法

一、SIFT特征检测概述 SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换,由加拿大教授David G.Lowe提出的。SIFT特征具有对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。 1.1 SIFT算法具的特点 图像…

平衡搜索树——AVL树小记

文章目录二叉搜索树平衡搜索树AVL树定义AVL中平衡(Balance)因子的定义AVL树插入规则AVL树失衡情况左左失衡/右右失衡左右失衡RL失衡代码左旋-调整平衡插入调整平衡因子AVL树正确性的验证二叉搜索树 理想情况下,二叉搜索树的查找时间复杂度是0(log(n)) 但是&#xff…

Linux 进程概念 —— 初识操作系统(OS)

文章目录1. 概念2. 设计操作系统的目的3. 定位4. 如何理解管理5. 再谈操作系统🍑 硬件部分🍑 操作系统🍑 驱动程序🍑 用户部分🍑 系统调用接口🍑 用户接口操作6. 总结1. 概念 任何计算机系统都包含一个基本…

HTML5基础汇总

目录 一,html5文档头部 1.页面标题及字符集的收集 (1).title标签 (2).charset属性 2.元信息的设置 (1).meta标签的作用 (2).http-equiv/content (2&am…

数据结构堆介绍,图文详解分析——Java/Kotlin双版本代码

堆介绍 堆是一种特殊的树结构。根据根节点的值与子节点值的大小关系,堆又分为最大堆和最小堆。 最大堆:每个节点的值总是大于或者等于其任意子节点的值。所以最大堆中根节点即为最大值。 最小堆:每个节点的值总是小于或者等于其任意子节点…

第六章课后题(LSTM | GRU)

目录习题6-3 当使用公式(6.50)作为循环神经网络得状态更新公式时,分析其可能存在梯度爆炸的原因并给出解决办法.习题6-4 推导LSTM网络中参数的梯度,并分析其避免梯度消失的效果​编辑习题6-5 推导GRU网络中参数的梯度,并分析其避免梯度消失的…

集合框架----源码解读Vector篇

1.vector官方简绍 Vector类实现了一个可增长的对象数组。与数组一样,它包含可以使用整数索引访问的组件。但是,Vector的大小可以根据需要增加或缩小,以适应在创建Vector之后添加和删除项。 每个向量都试图通过维护一个容量和一个capacityIncr…

C#设计模式详解(2)——Factory Method(工厂方法)

文章目录C#设计模式详解(2)——Factory Method(工厂方法)工厂方法模式1.1 概念1.2 意图1.3 问题1.4 解决方案1.5 工厂方法模式结构1.6 案例代码1.7 游戏开发中的应用C#设计模式详解(2)——Factory Method(工厂方法) 工厂方法模式…

领悟《信号与系统》之 非周期信号的傅里叶变换

非周期信号的傅里叶变换一、非周期信号的傅里叶变换二、 典型信号的傅立叶变换1.单边指数信号2.偶双边指数3. 矩阵脉冲信号4. 奇双边指数5. 符号函数6. 冲激信号7. 阶跃信号三、常用傅里叶变换表这里记录的信号都是非周期信号的傅里叶变化,频谱变换的特点就是&#…