专栏:力扣刷题录_1白天的黑夜1的博客-CSDN博客、企鹅程序员:Linux 系统与网络编程_1白天的黑夜1的博客-CSDN博客
目录
[1、链表中节点的数目范围是 [0, 5000]](#1、链表中节点的数目范围是 [0, 5000])
[2、-5000 <= Node.val <= 5000](#2、-5000 <= Node.val <= 5000)
边界情况:先遍历到最后,如果节点为空,返回nullptr;如果节点的next为空,则返回节点本身。
第一步,先通过head的next找到返回的新头节点,也就是图中值为5的节点,然后让它的next指向head也就是值为4的节点;
第二步,将head的next改为nullptr,完成反转,然后继续向上返回。
总结一下:两种视角虽不同,但最后写出来的代码都是一样。如果对于宏观视角理解起来困难的读者,可以看一看第二种视角,把链表看作一颗树。
结合两种视角和自己的思路,可以先去尝试一下编写代码,来提升自己的代码水平,题目链接如下
看到最后,如果对您有所帮助,还请点赞、收藏和关注一键三连,在未来还会继续带来优秀的内容,感谢观看,我们下期再见!
一、题目解析

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为空,则返回节点本身。
结合两种视角和自己的思路,可以先去尝试一下编写代码,来提升自己的代码水平,题目链接如下
三、代码示例
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为例子。

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