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)找出单链表的中间节点,以便将单链表一分为二;
2)将单链表后半部分逆置;
3)交叉合并两个子链表。
代码如下:
class Solution {
public:
//返回单链表的中间节点
ListNode *findMidNode(ListNode *head)
{
if(head == NULL)return NULL;
ListNode *fast = head;
ListNode *slow = head;
while(fast->next && fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
//单链表逆序
ListNode *reverse(ListNode *head)
{
if(head == NULL)return NULL;
ListNode *tail = NULL;
ListNode *nxt = NULL;
while(head != NULL)
{
nxt = head->next;
head->next = tail;
tail = head;
head = nxt;
}
return tail;
}
//交叉合并两个单链表
ListNode *crossMerge(ListNode *head1,ListNode *head2)
{
if(head1 == NULL)return NULL;
if(head2 == NULL)return NULL;
//设置辅助头结点,可在第一次插入节点时避免判断是否是头结点
ListNode dummy(0);
ListNode *tail = &dummy;
ListNode *p = head1;
ListNode *q = head2;
while(p && q)
{
tail->next = p;
tail = p;
p = p->next;
tail ->next = q;
tail = q;
q = q->next;
}
if(p)
tail->next = p;
if(q)
tail->next = q;
return dummy.next;
}
void reorderList(ListNode *head)
{
if(head == NULL || head->next == NULL)return;
ListNode *mid_node = findMidNode(head);
ListNode *head2 = mid_node->next;
head2 = reverse(head2);
mid_node->next = NULL;
head = crossMerge(head,head2);
return;
}
};
总结+牢骚:我觉得无论单链表的问题如何改变,差不多都可以将其划分为若干个基本子问题。这道题就是一个很典型的栗子。在找工作之前有必要把leetcode上关于单链表的题目多刷几遍!!!刷完题之后就写个leetcode单链表题目的总结吧!
原文地址:http://blog.csdn.net/u012118523/article/details/24661037