025. Reverse Nodes in k-Group
At a Glance
- Topic: linked-list
- Pattern: In-place Linked List Reversal
- Difficulty: Hard
- Companies: Microsoft, Amazon, Google, Meta, Bloomberg
- Frequency: High
- LeetCode: 25
Problem (one-liner)
Given singly linked list head and integer groupSize, reverse the nodes of the list k at a time, leave remaining nodes (if fewer than k) in original order.
Recognition Cues
- Reverse every k nodes — not whole list
- Need to detect full group before reversing
- Pointer surgery after [206] → extension
Diagram
At-a-glance flow (replace with problem-specific Mermaid as you refine this note). camelCase node IDs; no spaces in IDs.
Loading diagram…
Approaches
- Brute / cheating — allocate new nodes mirroring reversed chunks —
O(n)extra structures; violates “in-place” spirit. - Acceptable — collect values per group into slices, reverse arrays, rewrite
.Val—O(n)space, acceptable only if pointer mutation is banned for some reason. - Optimal — pointer-reverse each full
[groupBefore.Next … kth]segment to(groupAfter)exclusively —O(n)time /O(1)extra; partial tail left untouched after lookahead finds< groupSizenodes.
Optimal Solution
Go
type ListNode struct {
Val int
Next *ListNode
}
func reverseKGroup(head *ListNode, groupSize int) *ListNode {
dummy := &ListNode{Next: head}
groupBefore := dummy
for {
kth := groupBefore
for count := 0; count < groupSize; count++ {
kth = kth.Next
if kth == nil {
return dummy.Next
}
}
groupAfter := kth.Next
firstOfGroup := groupBefore.Next
reversedHead := reverseSegment(firstOfGroup, groupAfter)
groupBefore.Next = reversedHead
groupBefore = firstOfGroup
groupBefore.Next = groupAfter
}
}
func reverseSegment(start *ListNode, stop *ListNode) *ListNode {
var previous *ListNode
current := start
for current != stop {
next := current.Next
current.Next = previous
previous = current
current = next
}
return previous
}JavaScript
function reverseKGroup(head, groupSize) {
const dummy = { val: 0, next: head };
let groupBefore = dummy;
while (true) {
let kth = groupBefore;
for (let count = 0; count < groupSize; count++) {
kth = kth.next;
if (kth === null) {
return dummy.next;
}
}
const groupAfter = kth.next;
const firstOfGroup = groupBefore.next;
const reversedHead = reverseSegment(firstOfGroup, groupAfter);
groupBefore.next = reversedHead;
groupBefore = firstOfGroup;
groupBefore.next = groupAfter;
}
}
function reverseSegment(start, stop) {
let previous = null;
let current = start;
while (current !== stop) {
const next = current.next;
current.next = previous;
previous = current;
current = next;
}
return previous;
}Walkthrough
1→2→3→4→5, k=2 → 2→1→4→3→5
Find kth node in group; reverse [start, groupAfter); stitch.
Invariant: groupBefore always points to node before current block; partial tail triggers early exit.
Edge Cases
k == 1— no change- Length not divisible by
k— suffix untouched - Exactly one group equal to list length — full reverse
Pitfalls
- Off-by-one on
kthadvance — must land on last node of group beforegroupAfter - Forgetting to reconnect
firstOfGroup(now tail of reversed chunk) to rest
Similar Problems
- 206. Reverse Linked List — full reversal (Easy stepping stone).
- 92. Reverse Linked List II — reverse range
[left, right](Medium). - 23. Merge k Sorted Lists — different Hard on lists.
Variants
- Reverse alternate k-group — toggle reverse/skip pattern.
- Swap every k for array — two-pointer block swap.
- Very large k — same algorithm; watch stack if recursive.
Mind-Map Tags
#linked-list #reverse-range #k-group #dummy-node #in-place #hard-pointer
Last updated on
Spotted something unclear or wrong on this page?