Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You may not modify the values in the list's nodes, only nodes itself may be changed.
Example 1:
Given 1->2->3->4, reorder it to 1->4->2->3.
Example 2:
Given 1->2->3->4->5, reorder it to 1->5->2->4->3.
思路:此题需要保存链表的倒序,然后每次连接两个节点。既然考虑倒序,那么可以使用栈老保存节点。由于新链表是正序与倒序交替,所以每次要添加两个节点,因此,当正序的节点遇到倒序的节点时,证明整个链表已经穿插完成。
public void reorderList(ListNode head) {
if(head == null) return;
Stack<ListNode> stack = new Stack<ListNode>();
ListNode H = head;
while(H != null){
stack.push(H);
H = H.next;
}
H = head;
while(H != null){
ListNode T = stack.pop();
T.next = null;
ListNode N = H.next;
H.next = T;
H = H.next;
if(H == null) break;
if(N == T) return;
H.next = N;
H = H.next;
}
}
当然,更好的方法是不使用栈,直接将后半链表反转,再交替穿插。不需要额外空间。
class Solution {
// solution 1: 看题解了,其实很简单。将后半部分逆序,然后交叉合并前后两部分
public void reorderList(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return;
}
ListNode mid = findMid(head);;
ListNode midNext = mid.next;
mid.next = null;
ListNode reversedHead2 = reverse(midNext);
crossingMerge(head, reversedHead2);
}
private ListNode findMid(ListNode head) {
// TODO: make sure the accurate pos of mid
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode reverse(ListNode head) {
if (head.next == null) {
return head;
}
ListNode prev = null;
ListNode cur = head;
while (cur != null) {
// backup
ListNode next = cur.next;
// reverse
cur.next = prev;
// iter
prev = cur;
cur = next;
}
return prev;
}
private void crossingMerge(ListNode head1, ListNode head2) {
while (head1 != null && head2 != null) {
// backup
ListNode head1Next = head1.next;
ListNode head2Next = head2.next;
// crossing merge
head2.next = head1.next;
head1.next = head2;
// iter
head1 = head1Next;
head2 = head2Next;
}
}