🧠
Better (Find Middle, Reverse Second Half, Merge)
💡 This approach improves space by doing all operations in-place. It uses the fast-slow pointer technique to find the middle, reverses the second half, then merges two halves. It is a classic linked list manipulation pattern.
Intuition
Split the list into two halves at the middle, reverse the second half, then merge nodes alternately from the first and reversed second half.
Algorithm
- Use fast and slow pointers to find the middle of the list.
- Reverse the second half of the list starting from the middle.
- Merge the first half and reversed second half by alternating nodes.
- Ensure the last node points to null to terminate the list.
💡 Each step is a common linked list operation; combining them carefully achieves the reorder without extra space.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reorderList(head):
if not head or not head.next:
return
# Find middle
slow, fast = head, head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
# Reverse second half
prev, curr = None, slow.next
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
slow.next = None
# Merge two halves
first, second = head, prev
while second:
tmp1, tmp2 = first.next, second.next
first.next = second
second.next = tmp1
first = tmp1
second = tmp2
# Driver code to test
if __name__ == '__main__':
n5 = ListNode(5)
n4 = ListNode(4, n5)
n3 = ListNode(3, n4)
n2 = ListNode(2, n3)
n1 = ListNode(1, n2)
reorderList(n1)
curr = n1
while curr:
print(curr.val, end=' ')
curr = curr.next
print()
Line Notes
slow, fast = head, headInitialize pointers to find middle
while fast.next and fast.next.next:Move fast twice as fast as slow to find middle
curr.next = prevReverse pointer direction to reverse second half
first.next = secondMerge nodes from first and second halves alternately
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
public class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null) return;
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode prev = null, curr = slow.next;
slow.next = null;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
ListNode first = head, second = prev;
while (second != null) {
ListNode tmp1 = first.next, tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
}
public static void main(String[] args) {
ListNode n5 = new ListNode(5);
ListNode n4 = new ListNode(4); n4.next = n5;
ListNode n3 = new ListNode(3); n3.next = n4;
ListNode n2 = new ListNode(2); n2.next = n3;
ListNode n1 = new ListNode(1); n1.next = n2;
new Solution().reorderList(n1);
ListNode curr = n1;
while (curr != null) {
System.out.print(curr.val + " ");
curr = curr.next;
}
System.out.println();
}
}
Line Notes
ListNode slow = head, fast = head;Initialize pointers to find middle node
while (fast.next != null && fast.next.next != null)Move fast pointer twice as fast as slow
curr.next = prev;Reverse second half by changing next pointers
first.next = second;Merge nodes from first and reversed second half
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
void reorderList(ListNode* head) {
if (!head || !head->next) return;
ListNode *slow = head, *fast = head;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
}
ListNode* prev = nullptr;
ListNode* curr = slow->next;
slow->next = nullptr;
while (curr) {
ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
ListNode* first = head;
ListNode* second = prev;
while (second) {
ListNode* tmp1 = first->next;
ListNode* tmp2 = second->next;
first->next = second;
second->next = tmp1;
first = tmp1;
second = tmp2;
}
}
int main() {
ListNode* n5 = new ListNode(5);
ListNode* n4 = new ListNode(4); n4->next = n5;
ListNode* n3 = new ListNode(3); n3->next = n4;
ListNode* n2 = new ListNode(2); n2->next = n3;
ListNode* n1 = new ListNode(1); n1->next = n2;
reorderList(n1);
ListNode* curr = n1;
while (curr) {
cout << curr->val << " ";
curr = curr->next;
}
cout << endl;
return 0;
}
Line Notes
ListNode *slow = head, *fast = head;Initialize pointers to find middle
while (fast->next && fast->next->next)Move fast pointer twice as fast as slow
curr->next = prev;Reverse second half by pointer reversal
first->next = second;Merge nodes from first and reversed second half
function ListNode(val, next = null) {
this.val = val;
this.next = next;
}
function reorderList(head) {
if (!head || !head.next) return;
let slow = head, fast = head;
while (fast.next && fast.next.next) {
slow = slow.next;
fast = fast.next.next;
}
let prev = null, curr = slow.next;
slow.next = null;
while (curr) {
let nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
let first = head, second = prev;
while (second) {
let tmp1 = first.next;
let tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
}
// Test
const n5 = new ListNode(5);
const n4 = new ListNode(4, n5);
const n3 = new ListNode(3, n4);
const n2 = new ListNode(2, n3);
const n1 = new ListNode(1, n2);
reorderList(n1);
let curr = n1;
while (curr) {
console.log(curr.val);
curr = curr.next;
}
Line Notes
let slow = head, fast = head;Initialize pointers to find middle node
while (fast.next && fast.next.next)Move fast pointer twice as fast as slow
curr.next = prev;Reverse second half by changing next pointers
first.next = second;Merge nodes from first and reversed second half
Each step (finding middle, reversing, merging) is O(n) and done in-place, so total O(n) time and constant extra space.
💡 For n=10, this means about 30 operations but no extra memory allocation besides pointers.
Interview Verdict: Accepted and optimal for in-place reorder
This is the preferred approach in interviews because it meets the in-place constraint and is efficient.