THN Interview Prep

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 .ValO(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 < groupSize nodes.

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=22→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 kth advance — must land on last node of group before groupAfter
  • Forgetting to reconnect firstOfGroup (now tail of reversed chunk) to rest

Similar Problems

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?

On this page