题目描述:
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}.
---------------------------------------------------------------------------------------------------------------------------------------
本题如果是用普通数组进行存储的线性表结构的话,很好处理,一个指针从前往后,一个从后往前,错开进行插入就可以了。但是对于单链表而言,从前往后遍历是可以实现的,但是从后往前的遍历是不可能的,因此,就需要采用别的办法进行合并。
由于题目要求L0连接Ln,L1连接Ln-1,因此我们可以将链表的后半部分进行逆序,然后两个指针,一个指向头,一个指向逆序后头结点,然后进行错开插入,最终就可以得到结果了。
/**
* 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 == NULL || head->next == NULL || head->next->next == NULL)
return;
//首先找到链表的中间节点
ListNode *mid = midNode(head);
ListNode *r = reverseList(mid->next);
mid->next = NULL;
head = merge(head, r);
}
ListNode* reverseList(ListNode *head)
{
if(head == NULL || head->next == NULL)
return head;
ListNode *pre = NULL;
ListNode *cur = head;
ListNode *cur_next = head->next;
while(cur->next != NULL)
{
cur->next = pre;
pre = cur;
cur = cur_next;
cur_next = cur_next->next;
}
//还有最后一个节点没有逆序
cur->next = pre;
return cur;
}
//找到链表的中间节点
ListNode *midNode(ListNode *head)
{
ListNode *slow = head;
ListNode *fast = head->next;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
ListNode *merge(ListNode *l, ListNode *r)
{
//将两个链表错开插入,一般来说length(l) - length(r)要么为0,要么为1
ListNode *newhead = new ListNode(0);
ListNode *p = newhead;
//错开合并两个链表
while(r != NULL)
{
p->next = l;
l = l->next;
p = p->next;
p->next = r;
r = r->next;
p = p->next;
}
//最后要么l为空,要么还有一个元素,因此将p的下一个节点指向l
p->next = l;
return newhead->next;
}
};