Problem
Given a singly linked list L: L0 → L1 → … → Ln-1 → Ln
reorder it to: L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …
Example
Given 1->2->3->4->null
, reorder it to 1->4->2->3->null
.
Challenge
Can you do this in-place without altering the nodes' values?
Note
链表题目的集合:双指针法找中点,分割,合并,翻转,排序。哈,都在这一题里面了。
主函数reorderList():
对于长度为0或1的链表,返回;找到中点mid
;分割链表并翻转后半段为tail
;与前半段head
合并。
找中点findMid():
快慢指针,当fast == null || fast.next == null
时,返回慢指针。
翻转reverse():
建立空链表结点pre
,先存head.next
为temp
,令head
指向pre
,令pre
等于head
,再令temp
为head
。这样翻转就会令链表的首元素head
移动到尾部,并让pre
移动到所有已翻转结点的头部。当head
移动到最后一个元素null
,pre
正好移动到整个链表的头部。返回pre
,翻转完毕。
合并merge():
建立新链表结点dummy
,复制到新链表结点cur
。用index
判断当前结点是奇数还是偶数。偶数则加入n1
的结点,n1
后移;否则加入n2
的结点,n2
后移。每加入一个结点后,cur
后移。最后若n1
或n2
有剩余结点,则加入cur.next
。返回dummy.next
。
Solution
public class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null) return;
ListNode mid = findMid(head);
ListNode tail = reverse(mid.next);
mid.next = null;
merge(head, tail);
}
public ListNode findMid(ListNode head) {
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
public ListNode reverse(ListNode head) {
ListNode pre = null;
while (head != null) {
ListNode temp = head.next;
head.next = pre;
pre = head;
head = temp;
}
return pre;
}
public ListNode merge(ListNode n1, ListNode n2) {
int index = 0;
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while (n1 != null && n2 != null) {
if (index % 2 == 0) {
cur.next = n1;
n1 = n1.next;
}
else {
cur.next = n2;
n2 = n2.next;
}
index++;
cur = cur.next;
}
if (n1 != null) cur.next = n1;
else cur.next = n2;
return dummy.next;
}
}