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