题目要求
题解
https://github.com/soulmachine/leetcode
找到中间节点,断开,把后半截单链表 reverse 一下,再合并两个单链表。
class Solution {
public:
ListNode* reverse(ListNode *head){
if(!head||!head->next) return head;
ListNode *prev=head;
for(ListNode *cur=head->next,*next=cur->next;cur;
prev=cur,cur=next,next=next?next->next:nullptr){
cur->next=prev;
}
head->next=nullptr;
return prev;
}
void reorderList(ListNode* head) {
if(!head||!head->next) return;
ListNode *fast=head,*slow=head,*prev=nullptr;
while(fast&&fast->next){
prev=slow;
slow=slow->next;
fast=fast->next->next;
}
prev->next=nullptr; //从中切开
slow=reverse(slow);
//合并
ListNode *cur=head;
while(cur->next){
ListNode *tmp=cur->next;
cur->next=slow;
slow=slow->next;
cur->next->next=tmp;
cur=tmp;
}
cur->next=slow;
}
};
原谅我太菜,后边while循环里发生的情况单凭脑子真的想不来,所以,再次祭出playground。
看下这部分:
ListNode *cur=head;
while(cur->next){
ListNode *tmp=cur->next;
cur->next=slow; // @1
slow=slow->next;
cur->next->next=tmp; // @2
cur=tmp; // @3
}
cur->next=slow; // @4
ListNode *cur=head;
while(cur->next){
ListNode *tmp=cur->next;
cur->next=slow; // @1
out = listNodeToString(head);
cout << "@1 "<<out << endl;
slow=slow->next;
cur->next->next=tmp; // @2
out = listNodeToString(head);
cout << "@2 "<<out << endl;
cur=tmp; //@3
out = listNodeToString(head);
cout << "@3 "<<out << endl;
}
cur->next=slow; //@4
out = listNodeToString(head);
cout << "@4 "<<out << endl;
HeadBeforeReverse [1, 2, 3]
SlowBeforeReverse [4, 5, 6, 7]
SlowAfterReverse [7, 6, 5, 4]
@1 [1, 7, 6, 5, 4]
@2 [1, 7, 2, 3]
@3 [1, 7, 2, 3]
@1 [1, 7, 2, 6, 5, 4]
@2 [1, 7, 2, 6, 3]
@3 [1, 7, 2, 6, 3]
@4 [1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
不偷懒了,总结一下
- ListNode *cur=head;cur指向表头,如本例的1;
- ListNode *tmp=cur->next;tmp保存本轮要移后的节点(cur的下一个节点),如本例[1,2,3],
cur:1 tmp:2 本轮结束时相对位置应为[1,7,2],中间插入了另一半链表中slow指向的节点。 - cur->next=slow;当前cur指向另一半链表中slow指向的节点,如[1,2,3]->[1, 7, 6, 5, 4]
- slow=slow->next; slow指针后移,如[7,6,5,4]中slow由7到6
- cur->next->next=tmp; 把之前保存的节点插到cur后两步的位置,如将2插入[1, 7, 6, 5, 4]得
[1, 7, 2, 3],注意此时会把前半部分的剩余部分也带上。 - cur=tmp;将cur指针移到保存的节点的位置,如[1, 7, 2, 3]中,由1移动到2
- 重复2~6直到cur移出前半部分,如[1,2,3]
- 跳出循环后 cur->next=slow;无论链表为奇或偶,只需将后半链表的剩余部分拼接到cur后面,后半部分最后会剩下一个或两个元素,如果是两个也无需担心,因为这个元素无论被分在哪个部分都只会在最后面,不影响最终结果。