LeetCode #25 — Hard

Reverse Nodes
in k-Group

A complete visual walkthrough of iterative k-group linked list reversal — from brute force to optimal O(1) space.

Patterns Used

Roadmap

  1. Brute Force — Store and Rebuild
  2. The Core Insight — Process k at a Time
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Java Code
  6. Interactive Demo
  7. Complexity Analysis
Step 01

Brute Force — Store and Rebuild

The simplest approach: copy all node values into an array, reverse every consecutive group of k values in the array, then rebuild the linked list from the modified array.

Example: [1, 2, 3, 4, 5] with k = 3

original
1
2
3
4
5
↓ reverse groups of 3 in array ↓
reversed
3
2
1
4
5

First 3 values are reversed. The last 2 values (less than k) remain in their original order. Then rebuild a new linked list from this array.

This works but uses O(n) extra space for the array. The problem specifically asks: "Can you solve the problem in O(1) extra memory space?" We need to reverse the links in-place.

💡

The real challenge: Reversing a section of a linked list is straightforward. The tricky part is reconnecting each reversed group to the previous group and the next group without losing any references.

Step 02

The Core Insight — Process k at a Time

We process the list in groups of k nodes. For each group, we perform four sub-steps:

The Four Sub-Steps

1. Check if k nodes remain
Walk forward k steps from the current position. If we hit null before k steps, stop — the remaining nodes stay as-is.
2. Reverse the k nodes
Use the standard linked list reversal technique: for each node, point its next to the previous node.
3. Reconnect the reversed segment
The node before the group now points to the new first node (formerly the k-th node). The old first node (now last in the group) points to the rest of the list.
4. Advance to the next group
Move groupPrev to the end of the just-reversed group (the old first node). Repeat.

Why a dummy head? The first group has no "previous node." A dummy node before the head gives us a uniform groupPrev pointer for every group, including the first one. This eliminates special-case handling.

Before and After: One Group Reversal (k = 3)

before
prev
1
2
3
next
after
prev
3
2
1
next

Notice how prev now points to node 3 (the new head of the group), and node 1 (the old head, now the tail) points to next (the start of the unreversed portion). The groupPrev pointer then advances to node 1.

Step 03

Algorithm Walkthrough

Let's trace through [1, 2, 3, 4, 5] with k = 3 step by step.

Initial State

We create a dummy node pointing to the head. groupPrev starts at the dummy.

dummy
1
2
3
4
5
→ null
groupPrev = dummy

Iteration 1 — Check: Do 3 nodes remain?

Starting from groupPrev (dummy), walk 3 steps: dummy→1→2→3. We reach node 3, so kth = 3. Three nodes remain — proceed with reversal.

dummy
1
2
3
|
4
5
→ null
group to reverse: [1, 2, 3]

Iteration 1 — Reverse [1, 2, 3]

Reverse the pointers within the group. prev starts as groupNext (node 4), so node 1 will point to node 4 after reversal.

step 1: curr=1, point 1→4
3
2
1
4
step 2: curr=2, point 2→1
3
2
1
4
step 3: curr=3, point 3→2
3
2
1
4

Iteration 1 — Reconnect

Set groupPrev.next = kth (dummy→3) and advance groupPrev to the old first node (node 1, now at the tail of the reversed group).

dummy
3
2
1
4
5
→ null
groupPrev = node 1

Iteration 2 — Check: Do 3 nodes remain?

Starting from groupPrev (node 1), walk 3 steps: 1→4→5→null. We hit null before completing 3 steps, so kth = null. Only 2 nodes remain — not enough for a full group.

dummy
3
2
1
4
5
→ null
kth = null → break!

Final Result

3
2
1
4
5
→ null
Output: [3, 2, 1, 4, 5]
Step 04

Edge Cases

These are the scenarios you should keep in mind when implementing or testing:

  • k = 1 Every group has exactly 1 node. Reversing a single node is a no-op — the list is returned unchanged. Our algorithm handles this naturally since reversing 1 element does nothing.
  • k = n k equals the list length. The entire list is one group and gets fully reversed. Example: [1,2,3] with k=3 yields [3,2,1].
  • k > n k is greater than the list length. The getKth check fails immediately — no reversal happens. The list is returned as-is.
  • single node A list with only one node. For any k ≥ 1, either k=1 (no-op) or k>1 (not enough nodes). The result is always the same single node.
📋

Constraint reminder: The problem guarantees 1 ≤ k ≤ n, so k > n won't appear in LeetCode test cases. But a robust implementation handles it anyway — and ours does, for free.

Step 05

Full Annotated Java Code

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int val, ListNode next) {
 *         this.val = val; this.next = next;
 *     }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {

        // Dummy node simplifies head-of-list edge case
        ListNode dummy = new ListNode(0, head);
        ListNode groupPrev = dummy;

        while (true) {
            // 1. Find the k-th node from groupPrev
            ListNode kth = getKth(groupPrev, k);
            if (kth == null) break;  // fewer than k nodes left

            // 2. Save the node after this group
            ListNode groupNext = kth.next;

            // 3. Reverse the k nodes in this group
            //    prev starts at groupNext so the last reversed
            //    node points to the rest of the list
            ListNode prev = groupNext;
            ListNode curr = groupPrev.next;

            while (curr != groupNext) {
                ListNode next = curr.next;  // save next
                curr.next = prev;           // reverse pointer
                prev = curr;                // advance prev
                curr = next;                // advance curr
            }

            // 4. Reconnect: the old first node is now the tail
            ListNode tmp = groupPrev.next;  // old first (now tail)
            groupPrev.next = kth;           // point to new head (kth)
            groupPrev = tmp;                // advance to tail for next iteration
        }

        return dummy.next;
    }

    // Walk k steps from node; return null if fewer than k nodes remain
    private ListNode getKth(ListNode node, int k) {
        while (node != null && k > 0) {
            node = node.next;
            k--;
        }
        return node;
    }
}
💡

Key detail in the reversal loop: Notice prev starts as groupNext, not null. This is what seamlessly connects the tail of the reversed group to the rest of the list. Without this, node 1 would point to null instead of node 4, breaking the chain.

Step 06

Interactive Demo

Enter a list and a value for k, then step through the algorithm to see each group identified and reversed in real time.

⚙ k-Group Reversal Visualizer



Step 07

Complexity Analysis

Time
O(n)
Space
O(1)

Each node is visited at most twice: once during the getKth check and once during reversal. The total work across all groups is O(n). We use only a constant number of pointers — no arrays, stacks, or recursion.

Breakdown by Operation

GETKTH CALLS
O(n) total
Each of the n/k groups walks k steps. Plus the final check walks at most k steps.
REVERSALS
O(n) total
Each reversed group does exactly k pointer swaps. Across n/k groups: (n/k) * k = n swaps.
📝

Compared to brute force: The brute force approach also runs in O(n) time but requires O(n) extra space for the value array. Our in-place solution achieves the same time complexity with O(1) space — exactly what the problem asks for.