Linked List — Reversal Pattern: Algorithmic Intuition, Sub-patterns & C++ Guide
Reverse links in place with three pointers (prev, curr, next). Most hard list problems are "reverse a piece, then reconnect".
4 sub-patterns · 16 questions
What is this pattern?
A linked list is a chain of arrows. To reverse part of it you flip the arrows, one node at a time, and the hard part is never losing the rest of the chain. Linked List — Reversal is the family of problems where you reverse a whole list, a range, or blocks of k nodes, and then reconnect the pieces.
The core move is always the same: save next before you flip it. Flipping cur->next throws away the only link to the rest of the list. Every variant below is that move plus a question about where the reversed piece starts and ends.
A line of people holding hands, each facing forward. To reverse the line you turn each person around, one at a time, and you have to ask the next person to step forward before you let go of their hand. Reversing a range is the same, except the people at each end of the range must be reconnected to the rest of the line afterwards.
See it move
Two tracks: the reversed part (grows at the front) and the part still to do. The blue cell is the node whose arrow was just flipped. The arrow points back to the reversed part, so the rest of the list is never lost.
list = [1, 2, 3, 4, 5]step 1/6- prev
- null
- cur
- node 0 (val 1)
Nothing is reversed yet. cur is node 0 (val 1). Each step saves cur->next, flips cur->next to point at prev, then moves prev and cur one node forward.
The blue band is positions 2 to 5. The first node of the range (the pivot) never moves; each orange node is pulled to the front of the range. The node before the range is only used to reconnect.
list = [1, 2, 3, 4, 5, 6], left = 2, right = 5step 1/4- left
- 2
- right
- 5
- before
- node 0 (val 1)
- pivot
- 2
The node before the range is val 1. The first node of the range (val 2) stays put; the nodes after it jump to the front of the range one at a time.
How do I recognise it?
"Reverse the list", "reverse between position
leftandright", or "reverse everyknodes".Reorder the list: put the first half and the reversed second half back together (
L0 → Ln → L1 → Ln-1 …).Numbers stored as lists, most significant digit first (add two numbers, double a number): reverse, work from the units digit, then reverse back.
A removal rule that looks at the nodes to the right of each node ("remove a node if something bigger is after it"): reverse, process from the left, reverse back.
Rotate or split a list into pieces and join them in a new order.
The brute force copies the values into an array, reverses the array, and writes the values back into new nodes.
Looks like Linked List — Reversal, but isn't
Fast & Slow only reads positions. Reversal rewires next pointers. Palindrome and reorder use both: fast & slow find the middle, then reversal flips the second half.
An array can swap values at both ends with two indices. A singly linked list can't walk backwards, so each arrow must be flipped while the walk goes forward, with prev remembering where it came from.
Merging only takes the smaller head each time. Nothing reverses. Reorder uses a merge-like weave, but only after one half has been reversed.
How would I discover it from scratch?
Don't memorise “use linked list — reversal”. Ask these questions in order — the pattern falls out.
Copy all values into an array, reverse the array, and write the values back. That is O(N) extra space and it rebuilds nodes. Pointer reversal does the same job by flipping next in place with O(1) extra space.
Sub-patterns
Same core idea, different rule for “valid”. Learn them in this order.
Full reversal
5 questionsWalk once, flipping each arrow back to the node before it. The result is the list in reverse order, and the old tail is the new head.
Sublist reversal
3 questionsFind the node before the range, reverse exactly the range, then stitch both ends back. Everything outside the range stays as it was.
Groups of k
3 questionsRepeat the sublist reversal on each full block of k nodes. A short last block is either left alone or handled as the problem says.
Reordering / rotation
5 questionsSplit the list, reverse part of it, and re-weave or rotate the pieces. Draw the before and after pictures first; the rest follows from them.
Don't mix these up
Full reversal starts at the head and the old tail becomes the new head. Sublist reversal needs a node before the range, which is why a dummy node is used, and the nodes outside the range must not move.
After a block is reversed, its old first node is now the last node of that block, and it must point at the next block's head. The block itself reverses correctly; the link between blocks is what people forget.
Reorder List needs the first half cut from the second. Without slow->next = nullptr the two halves share a chain and the weave creates a cycle.
Code templates (C++)
Full reversal
Save nxt before cur->next = prev. The loop ends when cur is null, and prev is the new head.
// Full reversal: walk once, pointing each node back to the previous one.
// Returns the new head (the old tail).
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr; // the reversed part so far (empty at first)
ListNode* cur = head; // the next node to flip
while (cur != nullptr) {
ListNode* nxt = cur->next; // 1. save the rest of the list BEFORE losing it
cur->next = prev; // 2. flip this arrow
prev = cur; // 3. the reversed part now starts at cur
cur = nxt; // 4. move on to the saved node
}
return prev; // cur ran off the end, so prev is the old tail
}Sublist reversal (positions left to right)
Use a dummy node before the head. Walk to the node before left, then move the node after the pivot to the front of the range right - left times. Return dummy.next, because left = 1 changes the head.
// Sublist reversal: reverse nodes at positions left..right (1-based), keep the rest.
// Head insertion: walk to the node before the range, then pull the node after
// the pivot to the front of the range, one at a time.
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode dummy(0, head); // a fixed node before head, so left = 1 is no special case
ListNode* before = &dummy;
for (int i = 1; i < left; i++) before = before->next; // before = the node just before the range
ListNode* pivot = before->next; // the first node of the range; it stays put
for (int i = left; i < right; i++) { // right - left flips
ListNode* moved = pivot->next; // 1. the node that jumps to the front
pivot->next = moved->next; // 2. close the gap it leaves behind
moved->next = before->next; // 3. it points at the current front of the range
before->next = moved; // 4. it becomes the new front
}
return dummy.next; // the dummy's next is the new head
}Reverse in groups of k
Count k nodes ahead before touching anything. If the count falls short, stop. Otherwise reverse the block and join it to groupPrev. The old first node becomes the next groupPrev.
// Groups of k: reverse each full block of k nodes; a short last block stays as it is.
// Count k nodes ahead first. If the block is full, reverse it, then join it to the
// previous block's tail (the old first node of this block is now its last).
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode dummy(0, head);
ListNode* groupPrev = &dummy; // the node just before the current block
while (true) {
// 1. Is there a full block of k nodes starting after groupPrev?
ListNode* kth = groupPrev;
for (int i = 0; i < k && kth != nullptr; i++) kth = kth->next;
if (kth == nullptr) break; // fewer than k left: leave the rest alone
ListNode* groupNext = kth->next; // the node after this block (saved before relinking)
ListNode* first = groupPrev->next; // the old first node; it becomes the block's last
// 2. Reverse the block with head insertion (same as the sublist template).
ListNode* prev = groupNext; // the reversed block must end at groupNext
ListNode* cur = first;
while (cur != groupNext) {
ListNode* nxt = cur->next;
cur->next = prev;
prev = cur;
cur = nxt;
}
// 3. Join: the previous block now ends at the new first node (kth).
groupPrev->next = kth;
groupPrev = first; // the old first is this block's tail for the next round
}
return dummy.next;
}Split, reverse, and weave (reorder list)
Cut the first half from the second (slow->next = nullptr) before reversing. Without that cut the two halves still share a chain and the weave makes a cycle.
// Split, reverse, and re-weave: L0 → Ln → L1 → Ln-1 → L2 → …
// Three steps. Find the end of the first half, reverse the second half,
// then interleave the two halves one node at a time.
void reorderList(ListNode* head) {
if (head == nullptr || head->next == nullptr) return;
// 1. Find the end of the first half (fast and slow). slow stops on the first middle.
ListNode* slow = head;
ListNode* fast = head;
while (fast->next != nullptr && fast->next->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
// 2. Cut the list in two, then reverse the second half.
ListNode* second = slow->next;
slow->next = nullptr; // cut: without this the first half still runs into the second
ListNode* prev = nullptr;
while (second != nullptr) {
ListNode* nxt = second->next;
second->next = prev;
prev = second;
second = nxt;
}
second = prev; // head of the reversed second half (the old tail)
// 3. Weave: take one node from the first half, then one from the second, until one runs out.
ListNode* first = head;
while (second != nullptr) {
ListNode* f = first->next; // save both continuations before relinking
ListNode* s = second->next;
first->next = second; // L0 → Ln
second->next = f; // Ln → L1
first = f;
second = s;
}
}