原题链接: 92. 反转链表 II - 力扣(LeetCode)
tag: 链表.
在阅读本文前, 请先阅读如下一篇题解.
Leetcode 206. 反转链表 - 掘金 (juejin.cn)
一. 题目
给你单链表的头指针 head 和两个整数 left 和 right , 其中 left <= right . 请你反转从位置 left 到位置 right 的链表节点, 返回 反转后的链表 .
二. 题解
对于本题, 反转完链表后链表的头节点可能不变, 可能发生改变. 为此我们使用虚拟头节点 dummy 的技巧.
1. 设置虚拟头节点 dummy, 并将 prev 指针移动至反转起点的前驱位置
设置一个虚拟头节点 dummy , 并让 prev 指针从 dummy 开始移动.
ListNode* dummy = new ListNode(0, head), * prev = dummy;
将 prev 移动至反转起点下标 l 的前一个位置.
prev = prev->next;
重复这一步骤, 直到该 for 循环终止.
2. 对原链表需要反转的部分进行反转
ListNode* first = prev->next, * second = first->next;
保存 second 的后继节点.
ListNode* temp = second->next;
进行反转操作.
second->next = first;
更新 first 指针.
first = second;
更新 second 指针.
second = temp;
重复这一步骤, 直到该 for 循环终止.
3. 改变链表反转部分尾节点与 prev 节点 next 指针的指向
改变链表反转部分尾节点 next 指针的指向.
prev->next->next = second;
改变 prev 节点 next 指针的指向.
prev->next = first;
4. 返回反转链表后的头节点
head = dummy->next;
delete dummy;
return head;
三. 复杂度分析
时间复杂度: 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;
}
};