题目
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}
.
我的做法
超时的版本
一开始没想到正确的做法,写了个递归,结果超时,首先遍历到最后一个节点,然后将最后一个节点插入到第一个节点的后面,然后递归处理以第二个节点(移动最后一节点前的)为起始的链表,复杂度O(n^2),代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
if(!head)return;
ListNode*nextHead=head->next;
if(!nextHead)return;
ListNode *backPre=head;
while(backPre->next->next)
backPre=backPre->next;
if(backPre!=head){
backPre->next->next=head->next;
head->next=backPre->next;
backPre->next=NULL;
}
reorderList(nextHead) ;
}
};
改进后accept方法
突然想到昨天在写 链表的归并排序 时,用到了一个找链表中间节点的方法(快慢指针方法),这里可以使用这个方法找到中间节点,然后将后半部分的next指向逆向,构成一个以原链表尾节点为首节点的子链表,原链表变成了两个子链表,然后遍历一下子链表,将后半部分节点插入到相应位置即可,负责度是O(n),代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
typedef ListNode myListNode;
myListNode*getHalf(myListNode*head){//none head
if(!head||!head->next)
return head;
myListNode*slow=head;
myListNode*fast=head;
while(fast->next&&fast->next->next){
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
void reorderList(ListNode *head) {
ListNode* half=getHalf(head);
if(half==head)
return ;
ListNode*headBack=half->next;
half->next=NULL;
ListNode *pre=headBack;
ListNode *temp=headBack->next;
pre->next=NULL;
while(temp){
headBack=temp;
temp=temp->next;
headBack->next=pre;
pre=headBack;
}
temp=head;
while(headBack){
ListNode *tempBack=headBack->next;
headBack->next=temp->next;
temp->next=headBack;
temp=temp->next->next;
headBack=tempBack;
}
}
};
注意
1.LeetCode上的链表是没有头节点的,head指向第一个元素
2.getHalf返回的是第n/2+n%2个节点的指针(从1开始计数)。