Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes’ values.
For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.
解法1:笨重的方法 超时O(n^2)
就是不断从前往后遍历到头儿,每次遍历的长度都减小2个。
void reorderList(ListNode* head) {//笨重的方法 遍历了很多次!超时!!!
if(!head||!head->next||!head->next->next) return;
ListNode *l1=head,*l2=head->next,*r1=head->next,*r2=r1->next;
//l1被插入节点的前个节点 l2被插入节点的后一个节点 r1搜索节点中慢节点 r2搜索节点快节点找到最后一个节点
//r2->next=NULL代表r2位Ln,Ln-1,...... r1代表r2前一个节点
while(r2){
for(;r2->next;r1=r2,r2=r2->next);
l1->next=r2;
r2->next=l2;
r1->next=NULL;
l1=l2;
l2=l2->next;
if(l2==NULL) return;
r1=l2;
r2=r1->next;
}
}
解法2:时间O(n) 空间O(1)
找到中点,然后翻转后半部分。然后合并两个链表。注意合并截止条件。(类似 判断回文链表的题目)
//找出后一半 反转然后变成两个链表的合并
public:
void reorderList(ListNode* head){
if(!head) return;
ListNode* pMid=findMiddle(head);
ListNode* pNew=reverseList(pMid);
while(head->next&&pNew->next){
ListNode* nextNew=pNew->next;
pNew->next=head->next;
head->next=pNew;
head=pNew->next;
pNew=nextNew;
}
}
private:
ListNode* findMiddle(ListNode* head){
ListNode *slow=head, *fast=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
}
return slow;//奇数正好在中间,偶数正好在后一段开头;
}
//翻转链表 魔板
ListNode* reverseList(ListNode* head){
ListNode* p=NULL;
while(head){
ListNode* q=head->next;
head->next=p;
p=head;
head=q;
}
return p;
}