Skip to content
← All posts

Reverse Nodes in k-Group: Chunked Linked List Reversal

5 min read
leetcodeproblemhardlinked-lists

Reverse Nodes in k-Group is LeetCode problem 25 (hard). Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list.

k is a positive integer and is less than or equal to the length of the linked list. If the number of remaining nodes is not a multiple of k, leave them in their original order.

You may not alter the values in the nodes. Only the nodes themselves may be changed.

Example: [1, 2, 3, 4, 5] with k = 2 produces [2, 1, 4, 3, 5]. With k = 3 it produces [3, 2, 1, 4, 5].

original12345nullk = 221435nullk = 332145null
With k=2, pairs are reversed and the lone node 5 stays. With k=3, the first three nodes reverse and the remaining two stay.

This is a hard problem because it combines two things that are each tricky on their own: reversing a linked list segment in place, and stitching those reversed segments back together without losing references.

The approach

The algorithm breaks down into a repeating cycle of three operations:

  1. Count k nodes ahead. Starting from the current position, walk forward k steps. If you cannot reach k nodes, the remaining segment is too short to reverse. Leave it as-is and stop.
  2. Reverse the k-node chunk. Use the standard in-place linked list reversal on exactly k nodes. The old head of the chunk becomes the tail, and the old tail becomes the new head.
  3. Connect to the previous group. The node before the chunk (prev) needs its next pointer updated to point at the new head (old tail) of the reversed chunk. The new tail (old head) of the reversed chunk needs to point at whatever comes after the chunk.

Then advance prev to the new tail (old head of the chunk) and repeat.

A dummy node before the head gives you a stable anchor. The first group reversal changes the head of the list, and the dummy node handles that without any special case.

Visual walkthrough

Trace through reversing in groups of k = 3 on the list 1 -> 2 -> 3 -> 4 -> 5. The dummy node (labeled "d") sits before the list. Watch how the algorithm counts ahead, reverses, connects, and then checks the next group.

Setup: Create a dummy node. Check if k=3 nodes exist ahead.

d12345prevkth

prev = dummy. Count k=3 nodes forward from prev to find kth. Three nodes exist, so this group will be reversed.

Reverse group 1: Reverse the 3-node sublist in place.

d32145prev

Nodes 1, 2, 3 are reversed to 3, 2, 1. prev.next now points to 3 (the old tail). Node 1 (old head) links to node 4. prev advances to node 1.

Check group 2: Count k=3 nodes ahead from prev. Only 2 remain.

d32145prev

Starting from prev (node 1), only 2 nodes remain. That is fewer than k=3, so they stay as-is. Algorithm stops.

Done: Return dummy.next. The first group is reversed, the remainder is untouched.

32145

Final list: 3 -> 2 -> 1 -> 4 -> 5 -> null. The first k=3 nodes are reversed. Nodes 4 and 5 remain in original order.

The key insight: after reversing a group, the old head of that group is now the tail. That tail becomes prev for the next iteration, and its next pointer will be updated to point at the new head of the next reversed group.

The solution

def reverseKGroup(head, k):
    dummy = ListNode(0)
    dummy.next = head
    prev = dummy

    while True:
        kth = prev
        for _ in range(k):
            kth = kth.next
            if not kth:
                return dummy.next

        group_next = kth.next
        curr = prev.next
        nxt = curr.next

        for _ in range(k - 1):
            curr.next = nxt.next
            nxt.next = prev.next
            prev.next = nxt
            nxt = curr.next

        prev = curr

    return dummy.next

The inner loop runs k - 1 times, not k times. Reversing k nodes requires k - 1 pointer swaps. Each iteration moves one node from ahead of curr to the front of the group.

How the inner loop works

The reversal inside each group uses a technique where you repeatedly take the node after curr and move it to the front of the group. After the inner loop finishes, curr has moved from the front to the back of the group (it is now the tail), and prev.next points to the node that was originally at the back (now the head).

Here is what happens in each iteration of the inner loop:

  • nxt = curr.next grabs the next node to be moved
  • curr.next = nxt.next detaches nxt from its current position
  • nxt.next = prev.next attaches nxt at the front of the group
  • prev.next = nxt updates the entry point to the group

This is a variant of the standard linked list reversal that works within a bounded window. Instead of using prev/curr/next pointers that all advance forward, you keep curr stationary and repeatedly pull the next node to the front.

Complexity analysis

MetricValue
TimeO(n)
SpaceO(1)

Every node is visited a constant number of times. The counting pass walks through each node once. The reversal pass touches each node in the group once. No extra data structures are allocated beyond a few pointer variables.

The building blocks

This problem is built from two core building blocks:

In-place linked list reversal. The inner loop is the same pointer-swapping technique from Reverse Linked List, constrained to exactly k nodes instead of the entire list. If you can reverse a full linked list, you already know the core operation. The new part is knowing when to stop (after k - 1 swaps) and how to connect the reversed segment back into the surrounding list.

Group processing with a lookahead check. Before reversing, you walk k nodes ahead to confirm the group is complete. This count-then-act pattern prevents you from partially reversing a group that should remain untouched. The dummy node and prev pointer give you a uniform way to connect each reversed group without special-casing the first group.

Edge cases

  • k = 1. The counting loop always succeeds (one node exists), but the inner loop runs k - 1 = 0 times. No pointers change. The list is returned as-is. Correct.
  • k equals the list length. The entire list is one group. It reverses completely. The counting loop finds exactly k nodes, the inner loop reverses all of them, and the next counting pass hits null immediately. Correct.
  • Remaining nodes fewer than k. After reversing some groups, the counting loop reaches null before completing k steps. It returns dummy.next immediately. The remaining nodes stay in their original order. Correct.
  • Single node list. If k is 1, nothing changes. If k is greater than 1, the counting loop hits null on the first pass. Either way, the single node is returned. Correct.
  • Two nodes with k = 2. This reduces to Swap Nodes in Pairs. The algorithm handles it correctly as a single group of two.

From understanding to recall

You understand the counting pass, the inner reversal loop, and how prev stitches groups together. But can you write this solution from scratch without hesitation?

The tricky part is the four pointer assignments inside the inner loop. Which pointer gets updated first? What does curr point to after the loop? Where does prev advance to? These details matter, and getting one wrong means a broken list or an infinite loop.

The only way to make the four-line inner loop automatic is repetition. Type the solution from memory today, again in three days, again next week. By the fourth rep, the reversal pattern and the group-connection logic will feel natural.

Related posts

  • Reverse Linked List - The foundational in-place reversal technique that this problem uses inside each group
  • Swap Nodes in Pairs - The k=2 special case of this problem, using a simpler three-pointer swap per pair