LeetCode:链表逆序-递归法的层层分析

递归法的核心思想:利用递归的层级机制,下探到最低级别进行逆序,递归返回时层层逆序,最后到头节点时再逆序一次,逆序完成。

假设有链表A——>B——>C——>D——>nullptr。

递归到最低级别时开处理C,逆序CD,变为A——>B——>C<——D

处理B,逆序BC,变为A——>B<——C<——D

处理A,逆序AB,变为nullptr<——A<——B<——C<——D

到这里,把D当成新链表的头节点就行了。

这个流程中有个奇怪的地方,链表的最后一个节点明明是D,为什么从C开始逆序处理?网上很多文章和代码都没给出这点解释,也许因为原因很简单?既然是逆序,就必须要有两个节点才能做到,比如AB或者CD,而最后一个D无法和任何节点逆序,因为是单链表,所以D不知道有其他节点的存在,故逆序只能从C开始,C和D逆序。

OK,思想和流程都清楚了,接下来进行细节的处理。

递归的终止条件是什么?返回值是什么?

ListNode* reverseList(ListNode* head)
{
    if(what?)
        return what?;
}

可以看出,递归最后返回的一定是最后的D节点,把D节点当做函数返回的头节点,层层返回的节点也都是D,这样最后函数的返回值才是正确的。

终止条件很简单,只要最后到达D节点了,我们就把它返回,于是有如下代码

ListNode* reverseList(ListNode* head)
{
    //非法检测
    if(head == nullptr)
        return nullptr;
    //最后的D节点了
    if(head->next == nullptr)
        return head;
}

这样判断代码看起来逻辑很清楚,为使得代码更精简,很多网友会把代码等价转换为如下形式

ListNode* reverseList(ListNode* head)
{
	if ((head == nullptr) || (head->next== nullptr))
		return head;
}

终止条件和返回值有了,如何进行当前级别的逆序?

//逆序CD很简单
D->next = C;

回到具体的函数中,head就是所谓的C(为什么不能是D?因为如果是D,函数的前两行代码就返回了)C有了,D在哪?D就是C->next,所以代码变为

//逆序C和后续节点很简单
C->next->next = C;

再把C替换为head

//逆序head和后续节点很简单
head->next->next = head;

这样解释,这行代码是不是就太简单了!很多网友在解释递归法时一通代码扔出来,一上来就是head->next->next=head,让人看得云里雾里!这行代码的意思就是逆序当前节点和它的后续节点。

到此,函数代码大致变为

ListNode* reverseList(ListNode* head)
{
	if ((head == nullptr) || (head->next == nullptr))
		return head;

    ...
	head->next->next = head;
    ...
}

当前层级的逆序必须在下层逆序完成之后,所以代码继续衍变为

ListNode* reverseList(ListNode* head)
{
	if ((head == nullptr) || (head->next == nullptr))
		return head;

    //先逆序低级别的,lastNode就是最终的D节点
    ListNode* lastNode = reverseList(head->next);
	head->next->next = head;

    //始终返回D节点
    return lastNode;
}

至此似乎工作已经完成,我们检查一下

最后处理完A节点变为 A<——B<——C<——D,这里还有一个关键点,AB逆序后,B->next = A,那A的next是谁?如果完美逆序,A的next应该是nullptr,所以问题变为在什么地方把A的next设置为nullptr?再仔细分析一下,当我们一开始逆序CD后,D->next = C,要想设置C的next必须等待递归返回处理BC的时候再设置C->next = B,那么其实如果我们在逆序CD时设置C->next = nullptr好像并不影响B的处理,而且这也解决了A的next问题,即处理AB时,B->next = A,A->next = nullptr(因为A已经是最上层的了,没有OA逆序了,所以不存在A->next = O这种过程,最终A的next就是nullptr),于是代码继续衍变为

ListNode* reverseList(ListNode* head)
{
	if ((head == nullptr) || (head->next == nullptr))
		return head;

    //先逆序低级别的,lastNode就是最终的D节点
    ListNode* lastNode = reverseList(head->next);
	head->next->next = head;
    head->next = nullptr;

    //始终返回D节点
    return lastNode;
}

 至此,链表逆序的工作正式完成。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值