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