92. Reverse Linked List II
Decription
Reverse a linked list from position m to n. Do it in one-pass.
Note: 1 ≤ m ≤ n ≤ length of list.
Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
Analysis
先把长链表简化为三个元素的链表A->B->C,prev指向A,cur指向B,用以下语句进行反向:
third = cur->next;
cur->next = prev;
prev = cur;
cur = third;
此时链表变为A↔B C(注意A→B仍保留,最后再删除;B、C之间无箭头)。
然后cur = cur->next; prev = prev->next; 依次向后遍历所有在m到n之间的元素。
比如现在到了“A↔B C→D”,prev指向B,cur指向C。经过上述四条语句变换之后,实际上是BCD三个节点间的箭头变换,变为:“A↔B←C D”。这样依次遍历下去。
改变完m到n之间所有箭头方向之后,要将reversed sublink与未改动过的链表部分连接起来,也就是让子链表的最右边元素连到原链表左侧最后一个节点上;子链表最左边元素与原链表右侧第一个节点相连。
这个部分就需要在最开始设定两个指针con和tail,分别指向第m-1个节点(为了与子链表最后边元素connect)和第m个节点(是子链表改造之后的尾部节点,为了与原链表右侧第一个相连)。
还有一些细节处理,比如m=1时,head指针要在最后指向prev所指节点(否则结果会少节点)。
具体解决方案在solution里的图示非常清晰明了。
Code
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(m==n || head==NULL)
return head;
ListNode* prev = head; //= new ListNode(0);
//prev->next = head;
ListNode* cur = head->next;
ListNode* con = NULL;
ListNode* tail = NULL;
ListNode* third = cur;
int i=2;
while(i<m){
prev = prev->next;
cur = cur->next;
i++;
}
con = prev;
tail = cur;
while(i<=n){
third = cur->next;
cur->next = prev;
prev = cur;
cur = third;
i++;
}
if(m==1){
con->next = cur;
head = prev;
}
else{
con->next = prev;
tail->next = cur;
}
return head;
}
};