首页 > 代码库 > Reorder List

Reorder List

Problem:

Given a singly linked list L: L0 → L1 → ... → Ln-1 → Ln.

reorder it to: L0 → Ln → L1 → Ln-1 → ...

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}.

分析:

这个题目第一种做法是递归方式。每次只管头和尾的连接,然后递归做剩下的n-2个元素,又成了同样的问题。在这个算法中每次找尾部的元素都需要花费n的时间,而一共需要递归调用n/2次,所以算法的时间复杂度是O(n^2)的。代码可以写得很简单,但AC不过。

 1 class Solution {
 2 public:
 3     void reorderList(ListNode *head) {
 4         // none or just one
 5         if(head == NULL || head->next == NULL)
 6             return;
 7         
 8         // more than one, adjust the first and the last
 9         ListNode *pre = head, *tail = head->next;
10         while(tail->next != NULL) {
11             pre = pre->next;
12             tail = tail->next;
13         }
14         pre->next = NULL;
15         tail->next = head->next;
16         head->next = tail;
17         
18         // do it recursively
19         reorderList(tail->next);
20     }
21 };

第二种做法是将后一半的链表原地反转,然后再逐个遍历拼接到前一半的链表上。这种做法能够在O(n)的时间复杂度内完成。

寻找后一半的链表的算法在链表式的归并排序中也用过,思路是用快慢指针,一个一次走一步,另一个一次走两步,当走得快的到达末尾时,慢的也走到了中间。

链表原地反转的算法也很经典问题,三个指针,一个维护头部元素的指针(head2),一个维护新链表尾部的指针(tail),另外一个是将要插入到链表头部元素的指针(cur)。顺序从第二个元素开始,依次向后取每个元素,将其插入链表的头部。时间复杂度O(n)。

拼接两个链表的算法比较像归并两个集合的过程,只不过这里没有比较的过程,直接往后面接第二个链表。

 1 class Solution {
 2 public:
 3     void reorderList(ListNode *head) {
 4         // less than two elements
 5         if(head == NULL || head->next == NULL || head->next->next == NULL)
 6             return;
 7             
 8         // find the second half
 9         ListNode *slow, *fast;
10         slow = fast = head;
11         while(fast->next != NULL && fast->next->next != NULL) {
12             slow = slow->next;
13             fast = fast->next;
14             fast = fast->next;
15         }
16         
17         ListNode *head2 = slow->next;
18         slow->next = NULL;
19         
20         // reverse the second half
21         ListNode *tail = head2;
22         while(tail != NULL && tail->next != NULL) {
23             ListNode *cur = tail->next;
24             tail->next = cur->next;
25             cur->next = head2;
26             head2 = cur;
27         }
28         
29         // merge two parts
30         ListNode *head1 = head;
31         while(head1 != NULL && head2 != NULL) {
32             ListNode *p = head1, *q = head2;
33             head1 = head1->next;
34             head2 = head2->next;
35             q->next = p->next;
36             p->next = q;
37         }
38     }
39 };