92. Reverse Linked List II(反转链表 II)两种解法(C++ & 注释)

1. 题目描述

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

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

示例:

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

题目链接:中文题目英文题目

2. 迭代(Iteration)& 递归(Recursion)

2.1 解题思路

首先这题是206. 反转链表的升级版,而且上一题是本题的一种特殊情况,所以这题的解题思路和代码也可以用于上一题。我们先来看看几个例子:
在这里插入图片描述
我们发现两个重要的线索:

1)m->next都指向nNext;
2)如果m == head,返回n为头结点;反之,mPre->next = n,返回head为头结点;

所以说,我们只要找到这四个节点,就能完成整个链表的拼接。那么剩下的问题就只是如何翻转m ~ n范围内的链表了。首先,先找到m的节点,这个简单,直接for循环就能找到,顺带也找到了mPre。然后讲解一下主要的翻转思路,递归和迭代通用哒。初始化pre = nullptr, cur = mNode, next = mNode->next,遵循下面步骤:

  1. cur 指向 pre,完成翻转;
  2. pre指向cur,cur指向next,next指向next的下一个节点,m++;
  3. 重复1. 直到m == n + 1;

这里解释一下为什么是m == n + 1,而不是m == n。先来看看下面的流程图加深理解:
在这里插入图片描述
我们看到,B、C、D都要翻转一次,一共需要翻转三次,m - n = 4 - 2 = 2 + 1 = 3,所以m == n + 1;这部分对应代码:2.2.1 迭代(Iteration)

递归的翻转思路是一样哒,并木有太多的区别,大家看看代码理解一下就OK啦~ 有什么不明白的欢迎留言,有问必答哒~ 这部分对应代码:2.2.2 递归(Recursion)

2.2 实例代码

2.2.1 迭代(Iteration)

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        //if (!head) return nullptr; // 1 ≤ m ≤ n ≤ 链表长度

        ListNode* mNode = head, * mPreNode = nullptr;
        for (int i = 1; i < m && mNode; i++) { mPreNode = mNode; mNode = mNode->next; } // 找到m所指的节点

        assert(mNode);
        // 反转链表,并且找到n所指的节点
        ListNode* pre = nullptr, * cur = mNode, * next = mNode->next;
        while (m != n + 1) {
            cur->next = pre;
            pre = cur;
            cur = next;
            if (next) next = next->next;
            m++;
        }

        ListNode* nNode = pre, * nNext = cur; // 为了方便理解,用新的变量名
        mNode->next = nNext;
        if (mNode == head) return nNode;
        mPreNode->next = nNode;
        return head;
    }
};

2.2.2 递归(Recursion)

class Solution {
    ListNode* nNext = nullptr;

    // 函数重载
    ListNode* reverseBetween(ListNode* node, ListNode* pre, int count, int n) {
        ListNode* temp = node->next;
        node->next = pre;
        if (!temp || count == n) { nNext = temp; return node; }

        return reverseBetween(temp, node, count + 1, n);
    }

public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        //if (!head) return nullptr; // 1 ≤ m ≤ n ≤ 链表长度

        ListNode* mNode = head, * mPreNode = nullptr;
        for (int i = 1; i < m && mNode; i++) { mPreNode = mNode; mNode = mNode->next; } // 找到m所指的节点

        assert(mNode);
        ListNode* nNode = reverseBetween(mNode, nullptr, m, n);

        mNode->next = nNext;
        if (mNode == head) return nNode;
        mPreNode->next = nNode;
        return head;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值