LeetCode #25 Hard

Reverse Nodes in k-Group

Reverse the list k nodes at a time; a final group shorter than k stays as-is.

linked-listrecursion
Open on LeetCode ↗
02

Intuition

Reverse-a-list is the classic three-pointer flip. Here we do it in bursts of k, but only after checking k nodes exist — otherwise the tail group must stay untouched. A dummy node plus a groupPrev anchor makes each spliced group connect cleanly.

How to spot this pattern

Reverse-linked-list applied in blocks, with two additions: probe ahead to confirm a full group exists before touching anything, and use a dummy head so the first group needs no special case. The probe-then-act discipline is the general lesson — verify the whole operation is possible before performing any of it.

03

Approach

1

Probe before you flip

From groupPrev, walk k steps to find kth. If you run off the list, the remaining group is short — stop.

2

Reverse the group

Standard prev/curr reversal of exactly the k nodes, with prev initialized to the node after the group so the flipped group already points onward.

3

Reconnect and advance

The group's old first node becomes its last; groupPrev.next = kth and groupPrev moves to that old first node. Repeat.

04

Solution & live demo

1class Solution:
2 def reverseKGroup(self, head, k):
3 dummy = ListNode(0, head)
4 group_prev = dummy
5 while True:
6 kth = group_prev
7 for _ in range(k): # probe
8 kth = kth.next
9 if not kth: return dummy.next
10 group_next = kth.next
11 prev, curr = group_next, group_prev.next
12 while curr is not group_next: # reverse k nodes
13 nxt = curr.next
14 curr.next = prev
15 prev = curr
16 curr = nxt
17 tmp = group_prev.next # reconnect
18 group_prev.next = kth
19 group_prev = tmp
05

Common pitfalls

Reversing before confirming the group is complete

✗ Wrong
for _ in range(k):
    # reverse as you go
✓ Right
kth = group_prev
for _ in range(k):
    kth = kth.next
    if not kth: return dummy.next

A trailing partial group must be left untouched, but once you've started reversing you can't cheaply undo it. Probing first means you only commit when the full group is guaranteed.

Seeding prev with None instead of group_next

✗ Wrong
prev, curr = None, group_prev.next
✓ Right
prev, curr = group_next, group_prev.next

The reversed block's tail must point at the next group, not at null — otherwise the list is severed after the first block and everything beyond it is lost. Seeding with group_next splices the remainder on automatically.

Advancing group_prev after rewiring it

✗ Wrong
group_prev.next = kth
group_prev = group_prev.next
✓ Right
tmp = group_prev.next
group_prev.next = kth
group_prev = tmp

Reversal makes the group's old head its new tail, and that node is where the next group attaches. Reading group_prev.next after the rewire gives kth — the new head — so the pointer jumps to the wrong end of the block.

06

Edge cases

Length not divisible by k

The probe fails on the last group and it is left in original order.

k = 1

Every probe succeeds but reversal of one node is identity — list unchanged.

07

Complexity

Time
O(n)
Space
O(1)
Each node is visited twice (probe + flip).