leetcode92.反转链表II,多图详解思路,代码附带逐行注释,带你一步一步理解双指针算法

反转链表II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
示例 1:
在这里插入图片描述
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
其实做完反转链表后,该题的思路并不难想到,重点是如何确定边界条件,以及最后的逻辑处理。
如果没做过反转链表的话,建议先去做做,我有详细题解
1.创建哑节点:为了简化边界条件的处理,创建一个哑节点(dummy node),它的值初始化为0,并且将它的next指针指向头节点head。哑节点不包含在反转的范围内,但可以简化代码逻辑。

2.移动到反转起始位置:使用一个循环,将pre指针移动到反转开始的位置前一个节点(即第m-1个节点)。这样pre就指向了将要反转的子链表的前一个节点,而cur将指向第m个节点,即反转的起始节点。

相信到这里你就感觉很熟悉了,这不就是反转链表的逻辑吗?接下来开始执行反转。

3.执行反转:使用另一个循环,从第m个节点开始,直到第n个节点结束,进行节点的反转操作。在循环中:
(1).保存当前节点cur的下一个节点到nextTemp。
(2).将当前节点cur的next指针指向前一个节点prev,实现反转。
(3).更新prev为当前节点cur,即将当前节点加入到已反转的链表中。
(4).更新cur为nextTemp,即移动到下一个待反转的节点。

4.连接反转后的链表:在完成反转后,需要将反转子链表的尾部连接到原始链表的剩余部分。通过pre->next->next = cur;将反转子链表的最后一个节点的next指针指向原始链表中第n+1个节点。

5.更新哑节点的下一个节点:通过pre->next = prev;将哑节点的下一个节点更新为反转子链表的头节点,即第m个节点。

6.返回结果:最后,返回哑节点的下一个节点dummy->next,即更新后的链表的头节点。
其中较难理解的是第4步和第5步,这里建议读者自己画个图理解一下。
以示例1为例,我们执行完第三步后,反转部分应该为4=>3=>2,但这个部分与原链表还没有联系起来,如下面这个图所示,所以我们要将它们连接起来。
在这里插入图片描述

这是pre指向的是开始反转的前一个节点,故是1,然后1节点的next指向的是2,我们要将2的next指向5,所以代码表示为:

 pre->next->next = cur;

然后将1的next指向4,所以代码表示为:

pre->next = prev;

最后变成这样
在这里插入图片描述
看着难受?把箭头理一下,变成
在这里插入图片描述
完整代码如下:

class Solution {
public:
    // 函数用于反转链表中从位置m到位置n的节点
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        // 如果头节点为空,或者链表只有一个节点,或者m和n相等(即不需要反转),则直接返回头节点
        if (head == nullptr || head->next == nullptr || m == n) {
            return head;
        }

        // 创建一个哑节点,其next指向头节点head,用于简化链表操作
        ListNode* dummy = new ListNode(0);
        dummy->next = head;

        // pre指针用于指向将要反转的子链表的第一个节点的前一个节点
        ListNode* pre = dummy;
        
        // 移动pre指针到第m个节点的前一个节点
        for (int i = 1; i < m; ++i) {
            pre = pre->next;
        }

        // cur指针用于遍历需要反转的子链表
        ListNode* cur = pre->next;
        
        // prev指针用于指向已反转的子链表的最后一个节点,初始为NULL
        ListNode* prev = nullptr;

        // 从第m个节点开始,直到第n个节点,进行节点的反转操作
        for (int i = m; i <= n; ++i) {
            // 保存当前节点的下一个节点
            ListNode* nextTemp = cur->next;
            
            // 将当前节点的next指向prev,实现反转
            cur->next = prev;
            
            // 更新prev为当前节点,cur移动到下一个节点
            prev = cur;
            cur = nextTemp;
        }

        // 将反转后子链表的最后一个节点的next指向原始链表的剩余部分
        pre->next->next = cur;

        // 更新哑节点的下一个节点为反转后的子链表的第一个节点
        pre->next = prev;

        // 返回哑节点的下一个节点,即新链表的头节点
        return dummy->next;
    }
};

做完此题,可以看看

牛客OR152每k个一组反转链表
  • 32
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ciderw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值