Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-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}
.
My solution takes 3 steps:
1. use fast-slow points to cut the list in halves, which leading node p and q;
2. reverse the second half
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public void reorderList(ListNode head) {
if(head == null || head.next == null) return;
ListNode p = head, q = head;
ListNode prev = head;
while(p!=null && p.next !=null){
p = p.next.next;
prev = q;
q = q.next;
}
// e.g. 1-2-3-4-5 : q at 3
// e.g. 1-2-3-4: q at 2
// now cut the list
p = head;
prev.next = null;
// reverse the list led by q
q = reverse(q);
prev = null;
while(p!= null && q != null){
ListNode pnext = p.next;
ListNode qnext = q.next;
if(prev != null){
prev.next = p;
prev = q;
}else{
prev = q;
}
p.next = q;
q.next = null;
p = pnext;
q = qnext;
}
// note that the list led by q is longer
if(q != null){
prev.next = q;
}
}
private ListNode reverse(ListNode head){
ListNode p = head;
while(p.next != null){ p = p.next; }
ListNode ans = p;
ListNode q = head;
while(q != p){
ListNode qnext = q.next;
q.next = p.next;
p.next = q;
q = qnext;
}
return ans;
}
}
The space complexity is O(1): only points are used.
The time complexity is O(n): O(n) to cut and O(n) to reverse and O(n) to merge.
Solutions on line follow this pattern.
My follow-ups:
1. what if the list is doubly linked?
cut is the same, reverse and merge are more difficult.