问题描述
Given a singly linked list L: L 0→L 1→…→L n-1→L n,
reorder it to: L 0→L n →L 1→L n-1→L 2→L n-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}.
题目要求
解题思路
两个游标:一个用来指向下一次将要插入元素的位置,另一个用来遍历链表。从根结点开始遍历,如果当前节点的next节点不为空并且next的next节点不为空,则取最后一个节点插入到当前节点之后,游标一跳两个位置。直到游标一节点的next节点为空或者next的next节点为空。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.reorder.list;
import com.sort.linkedlist.ListNode;
public class Solution { public void reorderList(ListNode head) { if (head == null) { return; } if (head.next == null || head.next.next == null) { return; } ListNode pt = head; ListNode index = head; ListNode preIndex = head; while (pt.next != null && pt.next.next != null) { while (index.next != null) { preIndex = index; index = index.next; } preIndex.next = null; index.next = pt.next; pt.next = index; pt = pt.next.next; } } }
|
这种方法可行,但是每排序一个节点都需要遍历一次链表,效率比较低,可以看到下图,运行时间较长,占用内存已经 超过空间限制 了。
参考
看了一下网上给出的方案,几乎都是一样的:
这道链表重排序问题可以拆分为以下三个小问题:
使用快慢指针来找到链表的中点,并将链表从中点处断开,形成两个独立的链表。
将第二个链翻转。
将第二个链表的元素间隔地插入第一个链表中。
都是将链表拆成两个独立的链表进行重排序。
剽窃来的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
class Solution { public: void reorderList(ListNode *head) { if (!head || !head->next || !head->next->next) return; ListNode *fast = head; ListNode *slow = head; while (fast->next && fast->next->next) { slow = slow->next; fast = fast->next->next; } ListNode *mid = slow->next; slow->next = NULL; ListNode *last = mid; ListNode *pre = NULL; while (last) { ListNode *next = last->next; last->next = pre; pre = last; last = next; } while (head && pre) { ListNode *next = head->next; head->next = pre; pre = pre->next; head->next->next = next; head = next; } } };
|
时间空间使用都很少,性能问题没了。