Leetcode 92. 反转链表 II

249 阅读2分钟

原题链接: 92. 反转链表 II - 力扣(LeetCode)

tag: 链表.

在阅读本文前, 请先阅读如下一篇题解.

Leetcode 206. 反转链表 - 掘金 (juejin.cn)

一. 题目

给你单链表的头指针 head 和两个整数 left 和 right , 其中 left <= right . 请你反转从位置 left 到位置 right 的链表节点, 返回 反转后的链表 .

二. 题解

对于本题, 反转完链表后链表的头节点可能不变, 可能发生改变. 为此我们使用虚拟头节点 dummy 的技巧.

image.png

1. 设置虚拟头节点 dummy, 并将 prev 指针移动至反转起点的前驱位置

设置一个虚拟头节点 dummy , 并让 prev 指针从 dummy 开始移动.

ListNode* dummy = new ListNode(0, head), * prev = dummy;

image.png

将 prev 移动至反转起点下标 l 的前一个位置.

prev = prev->next;

image.png

重复这一步骤, 直到该 for 循环终止.

image.png

2. 对原链表需要反转的部分进行反转

ListNode* first = prev->next, * second = first->next;

image.png

保存 second 的后继节点.

ListNode* temp = second->next;

image.png

进行反转操作.

second->next = first;

image.png

更新 first 指针.

first = second;

image.png

更新 second 指针.

second = temp;

image.png

重复这一步骤, 直到该 for 循环终止.

image.png

3. 改变链表反转部分尾节点与 prev 节点 next 指针的指向

改变链表反转部分尾节点 next 指针的指向.

prev->next->next = second;

image.png

改变 prev 节点 next 指针的指向.

prev->next = first;

image.png

4. 返回反转链表后的头节点

head = dummy->next;

image.png

delete dummy;

image.png

return head;

image.png

三. 复杂度分析

时间复杂度: O(N), N 是链表的长度, 完成链表的反转需要遍历链表一次.

空间复杂度: O(1).

四. 代码

/**
 * 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 l, int r) {
        ListNode* dummy = new ListNode(0, head), * prev = dummy;    // 设置一个虚拟头节点 dummy , 并让 prev 指针从 dummy 开始移动
        for (int i = 0; i < l - 1; i ++) prev = prev->next;    // 将 prev 移动至反转起点下标 l 的前一个位置

        ListNode* first = prev->next, * second = first->next;    
        for (int i = 0; i < r - l; i ++) {    // 开始反转链表需要被反转的部分
            ListNode* temp = second->next;    // 保存 second 的后继节点
            second->next = first;    // 进行反转操作
            first = second;    // 更新 first 指针
            second = temp;    // 更新 second 指针
        }

        prev->next->next = second;    // 改变链表反转部分尾节点 next 指针的指向
        prev->next = first;    // 改变 prev 节点 next 指针的指向

        head = dummy->next;    // 返回反转链表后的头节点
        delete dummy;
        return head;
    }
};