力扣 82 反转链表② 【虚拟头结点】
全部刷题与学习记录
原题目
题目地址:92. 反转链表 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]
考查知识点
虚拟头结点可以避免对头结点进行操作的特殊情况分类讨论
自己的第一遍解法
思路确实是要保存反转链表的第一个节点leftNode
与其前一个节点Pre
、最后一个节点rightNode
与其下一个节点endNext
但是做的不好的地方有两点:
1、没有想到用虚拟头结点来避免对操作头结点特殊性的讨论
2、没有想到将反转的子链表先截断再反转,导致头尾的处理十分复杂
好的解法
参考:
https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/fan-zhuan-lian-biao-ii-by-leetcode-solut-teyq/
思路仍然是:保存反转链表的第一个节点leftNode
与其前一个节点pre
、最后一个节点rightNode
与其下一个节点endNext
但是加上了头结点、先截断后反转
需要复习的是:反转一般链表的方法reverseLinkedList()
,还是需要一前一后两个指针,不断更改指针指向的节点的next
之前写的 剑指 24 反转链表 ,加了注释
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 {
private:
//反转链表函数
void reverseLinkedList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while (cur != nullptr) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
}
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
//使用虚拟头结点避免对处理头结点的复杂分类讨论---重点
ListNode* dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode* pre = dummyHead;
//从虚拟头结点走left-1步,到leftPre
for (int i = 0; i < left-1; ++i) {
pre = pre->next;}
//从pre走right-left+1步,到right
ListNode* rightNode = pre;
for (int i = 0; i < right-left+1; ++i) {
rightNode = rightNode->next;}
//取出并切断子链表
ListNode* leftNode = pre->next;
ListNode* endNext = rightNode->next;
pre->next = nullptr;
rightNode->next = nullptr;
//反转子链表
reverseLinkedList(leftNode);
//将反转后的链表拼接回去
pre->next = rightNode;
leftNode->next = endNext;
return dummyHead->next;
}
};