递归-206.反转链表-力扣(LeetCode)

个人主页1白天的黑夜1-CSDN博客

专栏:力扣刷题录_1白天的黑夜1的博客-CSDN博客企鹅程序员:Linux 系统与网络编程_1白天的黑夜1的博客-CSDN博客

目录

一、题目解析

[1、链表中节点的数目范围是 0, 5000](#1、链表中节点的数目范围是 [0, 5000])

[2、-5000 <= Node.val <= 5000](#2、-5000 <= Node.val <= 5000)

二、算法原理

解法:递归

视角1:从宏观角度看待问题

即需经过三个阶段:

1、先将当节点后面的链表反转,返回一个新的头节点

2、将当前节点链接到反转的链表后

3、最后将当前节点的next置空

视角2:将链表看成一颗树,对其进行一次后序遍历

边界情况:先遍历到最后,如果节点为空,返回nullptr;如果节点的next为空,则返回节点本身。

根据返回的新头节点,将链表反转。

第一步,先通过head的next找到返回的新头节点,也就是图中值为5的节点,然后让它的next指向head也就是值为4的节点;

第二步,将head的next改为nullptr,完成反转,然后继续向上返回。

总结一下:两种视角虽不同,但最后写出来的代码都是一样。如果对于宏观视角理解起来困难的读者,可以看一看第二种视角,把链表看作一颗树。

如何编写递归代码?

1、重复的子问题->函数头设计

2、只关心某一个子问题做的什么->函数体设计

3、递归函数的出口

结合两种视角和自己的思路,可以先去尝试一下编写代码,来提升自己的代码水平,题目链接如下

三、代码示例

四、递归展开图

看到最后,如果对您有所帮助,还请点赞、收藏和关注一键三连,在未来还会继续带来优秀的内容,感谢观看,我们下期再见!


一、题目解析

1、链表中节点的数目范围是 [0, 5000]

2、-5000 <= Node.val <= 5000

二、算法原理

相信各位读者在学习链表这个数据结构的时候,已经学会了通过迭代(循环)的方式解决链表的反转,本篇博客如标题所示将会带来递归的解法,话不多说开始进入正文。

解法:递归

视角1:从宏观角度看待问题

为了方便更改改链接的指向,我们期望的是将头指针后的n-1个节点先反转,然后返回一个反转后的头指针,在剩下的n-1个节点,对于第二个节点,自然期望后n-2个节点先反转,然后返回一个头指针,一直这样递归下去,直到节点为空或者节点的next为空,即没有节点了和只有一个节点的情况,直接返回nullptr或节点本身,此时可以开始链接了。以最后一次更改举例,此时后n-1个节点反转后返回了新的头节点newhead,此时n-1个节点反转后的最后一个节点是第二个节点,通过head的next可以找到,让第二个节点的next指向head,使head称为新的尾节点,然后将head的next改为nullptr,返回新的头节点newhead,完成链表的反转。

即需经过三个阶段:
1、先将当节点后面的链表反转,返回一个新的头节点
2、将当前节点链接到反转的链表后
3、最后将当前节点的next置空

视角2:将链表看成一颗树,对其进行一次后序遍历

链表可以看作一棵特殊的树,将横着摆放的链表竖直摆放,此时再看就有点树的感觉了。后序遍历是一种二叉树的遍历方法,即先左子树、右子树、根的顺序遍历二叉树,与其相似的还有前序遍历和中序遍历,它们的区别在于根访问的位置,第一个就访问的根就是前序遍历,在中间就是中序遍历,在最后就是后序遍历。接下来看一看具体过程。

边界情况:先遍历到最后,如果节点为空,返回nullptr;如果节点的next为空,则返回节点本身。
根据返回的新头节点,将链表反转。
第一步,先通过head的next找到返回的新头节点,也就是图中值为5的节点,然后让它的next指向head也就是值为4的节点;
第二步,将head的next改为nullptr,完成反转,然后继续向上返回。

总结一下:两种视角虽不同,但最后写出来的代码都是一样。如果对于宏观视角理解起来困难的读者,可以看一看第二种视角,把链表看作一颗树。

如何编写递归代码?

1、重复的子问题->函数头设计

我们的重复子问题是,将当前节点后面的链表反转,所以需要一个ListNode*类型的变量。由于我们还需要返回新的头指针,所以返回值类型也是ListNode*。题目给我们提供的函数就可以拿过来直接用。

2、只关心某一个子问题做的什么->函数体设计

在链接当前指针和后面反转后的链表的操作,就是我们函数体内的内容。先用一个ListNode*类型的变量newhead接受递归函数的返回值,然后进行指针的修改,把当前节点链接到最后,并将其置空,最后返回newhead即可。

3、递归函数的出口

如果一个递归函数没有出口,会导致函数一直递归,导致栈溢出。经过上面的分析,当节点为空时,直接返回nullptr;如果节点的next为空,则返回节点本身。

结合两种视角和自己的思路,可以先去尝试一下编写代码,来提升自己的代码水平,题目链接如下

206. 反转链表 - 力扣(LeetCode)

三、代码示例

cpp 复制代码
class Solution {
public:
    //递归
    ListNode* reverseList(ListNode* head)
    {
        if(head == nullptr) return nullptr;
        if(head->next == nullptr) return head;
        ListNode* newhead = nullptr;
        newhead = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newhead;
    }
};

四、递归展开图

为了避免过于复杂(其实是博主懒画这么多递归展开图),使用1->2->3->nullptr为例子。

通过递归展开图,我们可以肯定递归函数能帮我们完成工作,所以我们要相信递归函数。

看到最后,如果对您有所帮助,还请点赞、收藏和关注一键三连,在未来还会继续带来优秀的内容,感谢观看,我们下期再见!

相关推荐
搬砖魁首5 小时前
基础能力系列 - 多线程2 - 条件变量
c++·rust·条件变量·原子类型·线程同步互斥
chase_my_dream5 小时前
C++ + SLAM 高频面试问题整理
开发语言·c++·面试
想要成为糕糕手5 小时前
前端必修课:JavaScript 数组与数据结构底层逻辑全解析
javascript·数据结构·面试
牛油果子哥q5 小时前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++
凡人叶枫7 小时前
Effective C++ 条款04:确定对象被使用前已先被初始化
java·linux·开发语言·c++·嵌入式开发
tyung7 小时前
Go 手写 Wait-Free SPSC 无界队列:无 CAS、无锁、泛型节点池
数据结构·后端·go
不想写代码的星星7 小时前
std::move 根本不移动,就像老婆饼里没有老婆
c++
redaijufeng7 小时前
C++雾中风景7:闭包
c++·算法·风景
Chen_harmony8 小时前
一、数据结构概念和复杂度计算
数据结构
小欣加油8 小时前
leetcode287寻找重复数
数据结构·c++·算法·leetcode