【LeetCode】C++ :中等题 - 链表 92. 反转链表 II

92. 反转链表 II

难度中等651

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

从labuladong大佬那学到的方法必须大赞!!!居然给我讲明白了递归,我哭了都,感动!!!

/**
 * 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* reverseBetween(ListNode* head, int m, int n) {
        if(m == 1){
            return reverseN(head, n);
        }
        head->next = reverseBetween(head->next, m-1, n-1);
        return head;
    }
    
    ListNode* successor = nullptr;
    ListNode* reverseN(ListNode* head, int n){
        if(n == 1){
            successor = head->next;
            return head;
        }
        ListNode* last = reverseN(head->next, n-1);
        head->next->next = head;    
        head->next = successor;
        return last;
    }
};

 

精讲

1、首先是reverse()函数,反转整个链表。

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

看到这个函数一开始觉得不可思议,递归解决的反转链表不是我能理解的。但后来在大佬的题解里面,看到

对于递归算法,最重要的就是明确递归函数的定义

在这个反转链表的递归函数里面,输入链表的head节点,将以head为起点的链表反转,然后返回之后的头结点。

紧接着看到的就是下面这个代码

       ListNode* last = reverse(head->next);

看到这我很容易就会到这个代码里面去想递归怎么递归的,然后然后。。。就陷进去了。

大佬题解中给出的建议是,不要跳进递归里去,要根据之前的函数定义,看看这段代码会产生什么结果。

想到这,这段代码产生的结果就是,把head->next 后面的所有节点都反转一下。

然后接着又是下面这个代码:

       head->next->next = head;   

这个有点绕,但是仔细理理就能弄清楚,就是把head的下一个节点的下一个节点指向自己,也就是反转链表里对head本身进行反转。至此链表已经全部反转完毕!

那么千万不要忘记,还要将head->next = nullptr,还要置为空。

总结一下这里面递归函数需要注意的地方:

递归函数需要有的基础条件:如果链表只有一个节点时,反转自己,直接返回。

        if(head == nullptr){
            return head;
        }

 

 

2. 接着是 reverseN()函数,这个函数是反转链表前N个节点。

    ListNode* successor = nullptr;
    ListNode* reverseN(ListNode* head, int n){
        if(n == 1){
            successor = head->next;
            return head;
        }
        ListNode* last = reverseN(head->next, n-1);
        head->next->next = head;    
        head->next = successor;
        return last;
    }

与上面函数定义是类似的道理,

不同的是 head->next = succressor, 将前N个节点都反转之后,head节点的下一个节点应该指向第N个节点之后的节点。

然后这里的基础条件是: 当只要反转前一个节点时,successor节点是等于头结点之后的节点,也就是第二个节点,这样是没有问题的。也就是反转一个元素,同时记录它的后驱节点。

并且这里的n 是不断减少的。所有基础条件n == 1 是没问题的。

 

3.  反转部分链表

如果m == 1 就是反转链表开头n个元素。如果m != 1, 把head的索引看成1,那么从第m 个元素开始反转;那么,head->next的索引看成1 那么就从第m-1个元素开始。后面一次类推。

    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if(m == 1){
            return reverseN(head, n);
        }
        head->next = reverseBetween(head->next, m-1, n-1);
        return head;
    }

 

感谢有这样写的很详细仔细的题解帮助,也感谢大佬们愿意分享这些去帮助他人,感谢!!!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值