LeetCode 143 Reorder List - Java Solution Explained
LeetCode 143 Reorder List - Java Solution Explained

LeetCode 143 Reorder List - Java Solution Explained

Learn how to solve LeetCode 143 Reorder List using Fast & Slow Pointer, Reverse Linked List, and Merge techniques in Java. Includes step-by-step dry run, time & space complexity analysis.

9 views
0
0
Listen to articleAudio version

Introduction

LeetCode 143 Reorder List is one of those problems that looks simple when you read it but immediately makes you wonder — where do I even start? There is no single trick that solves it. Instead it combines three separate linked list techniques into one clean solution. Mastering this problem means you have genuinely understood linked lists at an intermediate level.

You can find the problem here — LeetCode 143 Reorder List.

This article walks through everything — what the problem wants, the intuition behind each step, all three techniques used, a detailed dry run, complexity analysis, and common mistakes beginners make.

What Is the Problem Really Asking?

You have a linked list: L0 → L1 → L2 → ... → Ln

You need to reorder it to: L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → ...

In plain English — take one node from the front, then one from the back, then one from the front, then one from the back, and keep alternating until all nodes are used.

Example:

  1. Input: 1 → 2 → 3 → 4 → 5
  2. Output: 1 → 5 → 2 → 4 → 3

Node 1 from front, Node 5 from back, Node 2 from front, Node 4 from back, Node 3 stays in middle.

Real Life Analogy — Dealing Cards From Both Ends

Imagine you have a deck of cards laid out in a line face up: 1, 2, 3, 4, 5. Now you deal them by alternately picking from the left end and the right end of the line:

  1. Pick 1 from left → place
  2. Pick 5 from right → place after 1
  3. Pick 2 from left → place after 5
  4. Pick 4 from right → place after 2
  5. Pick 3 (only one left) → place after 4

Result: 1, 5, 2, 4, 3

That is exactly what the problem wants. The challenge is doing this efficiently on a singly linked list where you cannot just index from the back.

Why This Problem Is Hard for Beginners

In an array you can just use two pointers — one at the start and one at the end — and swap/interleave easily. But a singly linked list only goes forward. You cannot go backwards. You cannot easily access the last element.

This is why the problem requires a three-step approach that cleverly works around the limitations of a singly linked list.

The Three Step Approach

Every experienced developer solves this problem in exactly three steps:

Step 1 — Find the middle of the linked list using the Fast & Slow Pointer technique

Step 2 — Reverse the second half of the linked list

Step 3 — Merge the two halves by alternating nodes from each

Let us understand each step deeply before looking at code.

Step 1: Finding the Middle — Fast & Slow Pointer

The Fast & Slow Pointer technique (also called Floyd's algorithm) uses two pointers moving at different speeds through the list:

  1. slow moves one step at a time
  2. fast moves two steps at a time

When fast reaches the end, slow is exactly at the middle. This works because fast covers twice the distance of slow in the same number of steps.

ListNode fast = head;
ListNode slow = head;

while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
// slow is now at the middle

For 1 → 2 → 3 → 4 → 5:

  1. Start: slow=1, fast=1
  2. Step 1: slow=2, fast=3
  3. Step 2: slow=3, fast=5 (fast.next is null, stop)
  4. Middle is node 3

For 1 → 2 → 3 → 4:

  1. Start: slow=1, fast=1
  2. Step 1: slow=2, fast=3
  3. Step 2: fast.next.next is null, stop
  4. slow=2, middle is node 2

After finding the middle, we cut the list in two by setting slow.next = null. This disconnects the first half from the second half.

Step 2: Reversing the Second Half

Once we have the second half starting from slow.next, we reverse it. After reversal, what was the last node becomes the first — giving us easy access to the back elements of the original list.

public ListNode reverse(ListNode head) {
ListNode curr = head;
ListNode prev = null;
while (curr != null) {
ListNode next = curr.next; // save next
curr.next = prev; // reverse the link
prev = curr; // move prev forward
curr = next; // move curr forward
}
return prev; // prev is the new head
}

For second half 3 → 4 → 5 (from the first example):

  1. Reverse → 5 → 4 → 3

Now we have:

  1. First half: 1 → 2 → 3 (but 3 is the end since we cut at slow)
  2. Wait — actually after cutting at slow=3: first half is 1 → 2 → 3, second half reversed is 5 → 4

Let us be precise. For 1 → 2 → 3 → 4 → 5, slow stops at 3. slow.next = null cuts to give:

  1. First half: 1 → 2 → 3 → null
  2. Second half before reverse: 4 → 5
  3. Second half after reverse: 5 → 4

Step 3: Merging Two Halves

Now we have two lists and we merge them by alternately taking one node from each:

  1. Take from first half, take from second half, take from first half, take from second half...
ListNode orig = head; // pointer for first half
ListNode newhead = second; // pointer for reversed second half

while (newhead != null) {
ListNode temp1 = orig.next; // save next of first half
ListNode temp2 = newhead.next; // save next of second half
orig.next = newhead; // first → second
newhead.next = temp1; // second → next of first
orig = temp1; // advance first half pointer
newhead = temp2; // advance second half pointer
}

Why do we loop on newhead != null and not orig != null? Because the second half is always equal to or shorter than the first half (we cut at middle). Once the second half is exhausted, the remaining first half nodes are already in the correct position.

Complete Solution

class Solution {
public ListNode reverse(ListNode head) {
ListNode curr = head;
ListNode prev = null;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
public void reorderList(ListNode head) {
// Step 1: Find middle using fast & slow pointer
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
// Step 2: Reverse second half
ListNode newhead = reverse(slow.next);
slow.next = null; // cut the list into two halves
// Step 3: Merge two halves alternately
ListNode orig = head;
while (newhead != null) {
ListNode temp1 = orig.next;
ListNode temp2 = newhead.next;
orig.next = newhead;
newhead.next = temp1;
orig = temp1;
newhead = temp2;
}
}
}

Complete Dry Run — head = [1, 2, 3, 4, 5]

Step 1: Find Middle

List: 1 → 2 → 3 → 4 → 5
  1. Initial: slow=1, fast=1
  2. Iteration 1: slow=2, fast=3
  3. Iteration 2: fast.next=4, fast.next.next=5 → slow=3, fast=5
  4. fast.next is null → stop
  5. slow is at node 3

Step 2: Cut and Reverse

Cut: slow.next = null

  1. First half: 1 → 2 → 3 → null
  2. Second half: 4 → 5

Reverse second half 4 → 5:

  1. prev=null, curr=4 → next=5, 4.next=null, prev=4, curr=5
  2. prev=4, curr=5 → next=null, 5.next=4, prev=5, curr=null
  3. Return prev=5
  4. Reversed second half: 5 → 4 → null

Step 3: Merge

orig=1, newhead=5

Iteration 1:

  1. temp1 = orig.next = 2
  2. temp2 = newhead.next = 4
  3. orig.next = newhead → 1.next = 5
  4. newhead.next = temp1 → 5.next = 2
  5. orig = temp1 = 2
  6. newhead = temp2 = 4
  7. List so far: 1 → 5 → 2 → 3

Iteration 2:

  1. temp1 = orig.next = 3
  2. temp2 = newhead.next = null
  3. orig.next = newhead → 2.next = 4
  4. newhead.next = temp1 → 4.next = 3
  5. orig = temp1 = 3
  6. newhead = temp2 = null
  7. List so far: 1 → 5 → 2 → 4 → 3

newhead is null → loop ends

Final result: 1 → 5 → 2 → 4 → 3

Dry Run — head = [1, 2, 3, 4]

Step 1: Find Middle

  1. Initial: slow=1, fast=1
  2. Iteration 1: slow=2, fast=3
  3. fast.next=4, fast.next.next=null → stop
  4. slow is at node 2

Step 2: Cut and Reverse

  1. First half: 1 → 2 → null
  2. Second half: 3 → 4
  3. Reversed: 4 → 3 → null

Step 3: Merge

orig=1, newhead=4

Iteration 1:

  1. temp1=2, temp2=3
  2. 1.next=4, 4.next=2
  3. orig=2, newhead=3
  4. List: 1 → 4 → 2 → 3

Iteration 2:

  1. temp1=null (2.next was originally 3 but we cut at slow=2, so 2.next = null... wait)

Actually after cutting at slow=2, first half is 1 → 2 → null, so orig when it becomes 2, orig.next = null.

  1. temp1 = orig.next = null
  2. temp2 = newhead.next = null
  3. 2.next = 3, 3.next = null
  4. orig = null, newhead = null

newhead is null → stop

Final result: 1 → 4 → 2 → 3

Why slow.next = null Must Come After Saving newhead

This is a subtle but critical ordering detail in the code. Look at this sequence:

ListNode newhead = reverse(slow.next); // save reversed second half FIRST
slow.next = null; // THEN cut the list

If you cut first (slow.next = null) and then try to reverse, you lose the reference to the second half entirely because slow.next is already null. Always save the second half reference before cutting.

Time and Space Complexity

Time Complexity: O(n) — each of the three steps (find middle, reverse, merge) makes a single pass through the list. Total is 3 passes = O(3n) = O(n).

Space Complexity: O(1) — everything is done by rearranging pointers in place. No extra arrays, no recursion stack, no additional data structures. Just a handful of pointer variables.

This is the optimal solution — linear time and constant space.

Alternative Approach — Using ArrayList (Simpler but O(n) Space)

If you find the three-step approach hard to implement under interview pressure, here is a simpler approach using extra space:

public void reorderList(ListNode head) {
// store all nodes in ArrayList for random access
List<ListNode> nodes = new ArrayList<>();
ListNode curr = head;
while (curr != null) {
nodes.add(curr);
curr = curr.next;
}
int left = 0;
int right = nodes.size() - 1;
while (left < right) {
nodes.get(left).next = nodes.get(right);
left++;
if (left == right) break; // odd number of nodes
nodes.get(right).next = nodes.get(left);
right--;
}
nodes.get(left).next = null; // terminate the list
}

This is much easier to understand and code. Store all nodes in an ArrayList, use two pointers from both ends, and wire up the next pointers.

Time Complexity: O(n) Space Complexity: O(n) — ArrayList stores all nodes

This is acceptable in most interviews. Mention the O(1) space approach as the optimal solution if asked.

Common Mistakes to Avoid

Not cutting the list before merging If you do not set slow.next = null after finding the middle, the first half still points into the second half. During merging, this creates cycles and infinite loops. Always cut before merging.

Wrong loop condition for finding the middle The condition fast.next != null && fast.next.next != null ensures fast does not go out of bounds when jumping two steps. Using just fast != null && fast.next != null moves slow one step too far for even-length lists.

Looping on orig instead of newhead The merge loop should run while newhead != null, not while orig != null. The second half is always shorter or equal to the first half. Once the second half is done, the remaining first half is already correctly placed.

Forgetting to save both temp pointers before rewiring In the merge step, you must save both orig.next and newhead.next before changing any pointers. Changing orig.next first and then trying to access orig.next to save it gives you the wrong node.

How This Problem Combines Multiple Patterns

This problem is special because it does not rely on a single technique. It is a combination of three fundamental linked list operations:

Fast & Slow Pointer — you saw this concept in problems like finding the middle of a list and detecting cycles (LeetCode 141, 142).

Reverse a Linked List — the most fundamental linked list operation, appears in LeetCode 206 and as a subtask in dozens of problems.

Merge Two Lists — similar to merging two sorted lists (LeetCode 21) but here order is not sorted, it is alternating.

Solving this problem proves you are comfortable with all three patterns individually and can combine them when needed.

FAQs — People Also Ask

Q1. What is the most efficient approach for LeetCode 143 Reorder List? The three-step approach — find middle with fast/slow pointer, reverse second half, merge alternately — runs in O(n) time and O(1) space. It is the optimal solution. The ArrayList approach is O(n) time and O(n) space but simpler to code.

Q2. Why use fast and slow pointer to find the middle? Because a singly linked list has no way to access elements by index. You cannot just do list[length/2]. The fast and slow pointer technique finds the middle in a single pass without knowing the length beforehand.

Q3. Why reverse the second half instead of the first half? The problem wants front-to-back alternation. If you reverse the second half, its first node is the original last node — exactly what you need to interleave with the front of the first half. Reversing the first half would give the wrong order.

Q4. What is the time complexity of LeetCode 143? O(n) time for three linear passes (find middle, reverse, merge). O(1) space since all operations are in-place pointer manipulations with no extra data structures.

Q5. Is LeetCode 143 asked in coding interviews? Yes, frequently at companies like Amazon, Google, Facebook, and Microsoft. It is considered a benchmark problem for linked list mastery because it requires combining three separate techniques cleanly under pressure.

Similar LeetCode Problems to Practice Next

  1. 206. Reverse Linked List — Easy — foundation for step 2 of this problem
  2. 876. Middle of the Linked List — Easy — fast & slow pointer isolated
  3. 21. Merge Two Sorted Lists — Easy — merging technique foundation
  4. 234. Palindrome Linked List — Easy — also uses find middle + reverse second half
  5. 148. Sort List — Medium — merge sort on linked list, uses same split technique

Conclusion

LeetCode 143 Reorder List is one of the best Medium linked list problems because it forces you to think in multiple steps and combine techniques rather than apply a single pattern. The fast/slow pointer finds the middle efficiently without knowing the length. Reversing the second half turns the "cannot go backwards" limitation of singly linked lists into a non-issue. And the alternating merge weaves everything together cleanly.

Work through the dry runs carefully — especially the pointer saving step in the merge. Once you see why each step is necessary and how they connect, this problem will always feel approachable no matter when it shows up in an interview.

Ai Assistant Kas