首页 > 代码库 > Leetcode:Reverse Linked List II 反转链表区间

Leetcode:Reverse Linked List II 反转链表区间

Reverse Linked List II

Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:
Given   1->2->3->4->5->NULL,  m = 2 and n = 4,

return  1->4->3->2->5->NULL.

Note:
Given mn satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.

解题分析:这个题目就是很容易断链,需要使用多个暂存结点

首先,只要是单链表反转,我们最先应该想到的是 头插法

单链表的头插法是 逆序

单链表的尾插法是 正序

确定头插法之后,我们需要注意m可以等于1,这意味着,第一个节点也可能逆转,出现了 头节点和其余结点操作不统一的情况

这时,我们应该想到 为了是 头节点和其余结点操作统一起来 有两种办法:1. 二级指针  2. 虚拟一个前置结点指向 链表第一个节点

class Solution {
public:
    ListNode *reverseBetween(ListNode *head, int m, int n) {
        if (head == nullptr) return nullptr;
        assert(m >= 1 && n >= 1 && m <= n);
        if (m == n) return head;
        
        ListNode* newHead = new ListNode(0);
        newHead->next = head;
        ListNode* cur = newHead;
        for (int i = 0; i < m - 1; ++i) {
            cur = cur->next;
        }
        ListNode* prev = cur;
        cur = cur->next;
        ListNode* mthNode = cur;
        ListNode* mthHead = cur;
        ListNode* nextNode = cur->next;
        for (int i = 0; i < n - m; ++i) {
            cur = nextNode;
            nextNode = cur->next;
            cur->next = mthHead;
            mthHead = cur;
        }
        prev->next = mthHead;
        mthNode->next = nextNode;
        return newHead->next;
    }
};

我们以  1 --> 2 --> 3 --> 4 --> 5 --> NULL 为例

m = 2, n = 4

也就是我们需要逆转 2 --> 3 --> 4 

step1. 虚拟一个前置结点指向链表第一个节点

step2. 前进m-1步到达需要反转区间的前1个结点 即结点1,代码中对应的 prev指针

step3. 再前进1步,达到反转区间的第一个节点,设置两个暂存结点 mthHead 和 mthNode

mthHead始终指向区间 2 -->3 --> 4的头节点

step4. 然后前进n-m步,每前进一步都需要事先 把 cur->next 保存起来,防止断链

step5. 循环结束后, 链表表现为3段: 1(第1段)  4 --> 3 --> 2(第2段)  5-->NULL(第3段)

所以我们需要两次链接的操作,第1段和第2段链接使用预先暂存的prev指针,第2段和第3段链接使用预先暂存的 mthNode指针 

step6. 返回链表的第一个节点指针,即虚拟结点的next指针