What does it solve?
Reverse a linked list k nodes at a time. With k=2, 1→2→3→4→5 becomes 2→1→4→3→5. The trailing leftover group (fewer than k nodes) is left untouched.
Key insight: it's plain reversal applied per block, plus careful stitching. For each group: first check k nodes exist ahead (if not, stop). Reverse exactly those k. Then re-link: the previous group's tail must point to this group's new head, and this group's new tail (the old head) must point to whatever comes next. Get the stitching wrong and the list breaks: that's the whole difficulty.
The core idea
while k nodes remain ahead:
reverse those k nodes
prevTail.next = newHead
oldHead.next = nextGroup
prevTail = oldHead
leftover (< k) stays as-is
Complexity
Each node is checked once and reversed once. The k-node lookahead doesn't add an extra factor: total work is a constant number of passes over each node.
Iterative reversal with a few pointers per group. The recursive form instead costs O(N/k) stack frames.
Lists & edge cases
Step-by-step table
| Step | Group | Phase | Action | List so far |
|---|
C++ implementation
#include <bits/stdc++.h> using namespace std; struct ListNode { int val; ListNode* next; }; ListNode* reverseKGroup(ListNode* head, int k) { ListNode dummy; dummy.next = head; ListNode* prevTail = &dummy; // tail of the last finished group while (true) { // 1) check that k nodes remain ahead ListNode* check = prevTail; for (int i = 0; i < k && check; i++) check = check->next; if (!check) break; // fewer than k: leave as-is // 2) reverse exactly k nodes ListNode* prev = check->next; // first node AFTER the group ListNode* curr = prevTail->next; ListNode* groupHead = curr; // becomes the group's new tail for (int i = 0; i < k; i++) { ListNode* nxt = curr->next; curr->next = prev; prev = curr; curr = nxt; } // 3) stitch: prevTail -> newHead; advance prevTail prevTail->next = prev; // prev is the group's new head prevTail = groupHead; // old head is the new tail } return dummy.next; }
My Notes