Leetcode 92. 反转链表 II
题目传送门
解题思路:
首先,题目要求我们将一个单链表的特定区间内的节点反转,这个区间是不确定的(对于单链表的反转来说,可以先用206. 反转链表来练练手).
本题是没有空的头节点的,由于可能会涉及到头节点的操作,我们可以创建一个虚拟的节点来充当头节点,这样可以减少一些特殊情况,让我们的解法可以适用到更多的范围。然后我们来看一下反转的具体操作是什么。
我们反转的区间就是两个红色箭头的内部。我们看一下内部该怎么反转,我们需要将区间内部的节点的\(next\)都指向它的前一个节点,从图上看就是这样
因此我们就需要记录当前节点和其下一个节点。分别用\(cur\)与\(curNext\)来表示。然后每次反转之后,我们要将\(cur\)和\(curNext\)都向后移动到下一个节点,对于\(cur\)来说就是移动到\(curNext\),而\(curNext\)就是移动到其下一个节点,也就是\(curNext->next\)。
由于是区间内的反转,从图上也可以看出,我们还有节点没有连接上以及指针没有正确的指向,所以最后我们需要将开始反转节点的前一个节点\(pre\)的\(next\)指向我们反转后链表的头节点,将反转后链表的尾节点指向剩下没有被反转的区间。最后反转的效果就是这样:
代码:
code
/**
* 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 left, int right) {
if(left==right) return head;//特殊情况,也可以不用写
ListNode *dummy=new ListNode(0);
dummy->next=head;//创建虚拟头节点并连接
ListNode *pre=dummy;
for(int i=0;i<left-1;i++) pre=pre->next;
ListNode *cur=pre->next,*curNext=cur->next;
for(int i=0;i<right-left;i++)
{
ListNode *next=curNext->next;//记录下curNext下一步要移动到的位置
curNext->next=cur;
cur=curNext;//这里的顺序不能错,两个节点往后跳
curNext=next;
}
pre->next->next=curNext;//将链表连接起来
pre->next=cur;
return dummy->next;
}
};