Reverse Nodes in k-Group
Given the head of a linked list, reverse its nodes k at a time and return the modified head. Nodes are reversed in consecutive blocks of exactly k; if the final block has fewer than k nodes, it is left in its original order. Rewire nodes in place — do not change any node's value. Return the head of the fully rewired list.
- 1 <= k <= n <= 5000
- 0 <= Node.val <= 1000
- O(1) extra memory is required (no recursion stack).
head = [1,2,3,4,5], k = 2[2,1,4,3,5]head = [1,2,3,4,5], k = 3[3,2,1,4,5]head = [1,2], k = 1[1,2]This is Reverse Linked List with a boundary. There we flipped the entire chain; here we flip it in consecutive blocks of exactly k — [1,2,3,4,5] with k = 2 becomes [2,1,4,3,5]. Two new demands come with the boundary, and they are the whole content of this problem: a partial final block must be left untouched, and each reversed block must be stitched back to its neighbors so the list stays connected.
From Reverse Linked List we already own the reversal engine — the prev/curr/next_temp trio doing cache-flip-advance. The skeleton there had two open slots: where reversal starts and when it stops. For the whole list, it stopped at null. Here we fill the "stops" slot differently: run that same loop exactly k times instead of until null, and it reverses precisely one block, leaving curr parked on the first node of the next block. Nothing about the flip changes; we only change how many times it fires.
The one hard rule — a final block shorter than k stays in original order — forces a decision before any flipping: we must know a full k nodes exist ahead before we touch them. So each round begins by scouting k nodes forward. If we fall off the end during the scout, this block is short: we return it as-is and stop. Only after confirming k nodes do we reverse. Checking after reversing would be too late — we'd have already scrambled a block we were supposed to leave alone.
Reversing a block flips who is first and who is last: the block's original head becomes its tail, its original last node becomes its head. Welding means two joins per block — the previous block's tail must point to this block's new head, and this block's new tail (its original head) must point to whatever the next round produces. A dummy node before the real head gives the first block a "previous tail" to attach to, so the head-of-list join is no special case. We track group_prev = the tail of the last finished block.
dummy = Node(0, head)
group_prev = dummy
while True:
# 1. Scout: is there a full group of k ahead of group_prev?
kth = group_prev
for _ in range(k):
kth = kth.next
if not kth:
return dummy.next # short block: leave it, we're done
group_next = kth.next # first node AFTER this block
# 2. Reverse this block (the base engine, stopped at group_next)
prev, curr = group_next, group_prev.next
while curr != group_next:
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp
# 3. Weld. group_prev.next was this block's OLD head = its new tail.
old_head = group_prev.next
group_prev.next = kth # previous tail -> this block's new head
group_prev = old_head # advance to this block's new tailprev = group_next (not None): that single choice makes the block's new tail point straight at the untouched next block for free, so we never leave a dangling end mid-list. The remaining join — previous tail to this block's new head — is the one explicit rewire, group_prev.next = kth. Miss either weld and the list either breaks in half or points into an already-reversed region.Every node is scouted once and flipped at most once, so the work is O(N) time. The constraint demands O(1) space, which is why we write it iteratively: the tidy recursive version (reverse a block, then recurse on the rest) is correct but stacks up to N/k frames — that hidden stack is O(N) space and violates the requirement. The lesson generalizes past this problem: a known sub-routine (here, reversal) becomes a new problem when you add a boundary — where it starts, where it stops, how the pieces re-connect. Solve those three joins and you have reused the engine, not rebuilt it. Swap Nodes in Pairs is this exact problem frozen at k = 2.
Block-by-Block Reversal
counting nodes...