给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
这道链表重排序问题可以拆分为以下三个小问题:
-
使用快慢指针来找到链表的中点,并将链表从中点处断开,形成两个独立的链表。
-
将第二个链翻转。
-
将第二个链表的元素间隔地插入第一个链表中。
class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null || head.next.next == null)
return;
ListNode p = head;
ListNode q = head;
ListNode pr = null;
while (q != null && q.next != null) {
pr = p;
p = p.next;
q = q.next.next;
}
if (q == null){
pr.next = null;
p = reverse(p);
}
else {
ListNode ne = p.next;
p.next = null;
p = reverse(ne);
}
ListNode pre = p;
ListNode next = p;
ListNode cur = head;
while (pre != null) {
next = pre.next;
ListNode temp = cur.next;
cur.next = pre;
pre.next = temp;
cur = temp;
pre = next;
}
}
private ListNode reverse(ListNode head) {
ListNode p = head;
ListNode pre = head;
ListNode next = head;
while (p.next != null)
p = p.next;
while (next != p) {
next = pre.next;
ListNode temp = p.next;
p.next = pre;
pre.next = temp;
pre = next;
}
return p;
}
}
还有一种方法,思路同上,但是借助栈进行反转,先将所有元素入栈,算出要插入的节点个数,出栈插入,注意记得将出栈元素的指向它的指针断掉,否则会形成环导致内存溢出。
class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null || head.next.next == null)
return;
Stack<ListNode> stack = new Stack<ListNode>();
ListNode p = head;
while (p != null) {
stack.push(p);
p = p.next;
}
ListNode pre = head;
ListNode next = head;
int num = (stack.size()-1) / 2;
while (num > 0) {
ListNode cur = stack.pop();
ListNode peak = stack.peek();
peak.next = null;
next = pre.next;
pre.next = cur;
cur.next = next;
pre = next;
num--;
}
}
}