Reversing a Linked List (In-Place)
Overview
Reversing a linked list in-place means changing the next pointers so that the list runs in the opposite direction, using only O(1) extra space (a few pointers). You do not create new nodes or copy values; you only rewire pointers. This is a fundamental pattern that appears in many problems: palindrome check, reorder list, reverse nodes in k-group, and more.
Core idea: As you traverse the list, repeatedly take the current node and make it point to the "previous" node (the head of the already-reversed prefix). Then the old next node becomes the new current, and the current node becomes the new head of the reversed part.
When to Use In-Place Reverse
- Reverse the entire list β classic interview problem.
- Reverse part of the list β e.g. from a given node to the end, or a range [m, n].
- Palindrome linked list β find middle, reverse second half, compare.
- Reorder list β reverse second half then merge with first half.
- Reverse nodes in k-group β reverse each block of k nodes using the same pattern.
How It Works
- Keep three references:
prev(already reversed part's head, initially null),curr(current node, initially head), andnext(temporary, to not lose the rest of the list). - In each step: save
next = curr.next, setcurr.next = prev, then setprev = currandcurr = next. - When
curris null,previs the new head of the reversed list.
Invariant: After each step, the nodes from the original start up to (and including) the old curr are reversed; curr is the next node to process.
Example 1: Reverse the Entire List
Problem: Given the head of a singly linked list, reverse the list and return the new head.
function reverseList(head: ListNode | null): ListNode | null {
let prev: ListNode | null = null;
let curr: ListNode | null = head;
while (curr !== null) {
const next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}- Time: O(n), Space: O(1).
Example 2: Reverse a Sublist (from position m to n)
Problem: Reverse the nodes from position m to n (1-indexed). Leave the rest unchanged.
Find the node before the sublist (at index m-1), reverse the segment of length (n - m + 1), then reconnect the three parts: prefix, reversed segment, suffix.
function reverseBetween(head: ListNode | null, m: number, n: number): ListNode | null {
const dummy = new ListNode(-1);
dummy.next = head;
let prev: ListNode = dummy;
for (let i = 1; i < m; i++) prev = prev.next!;
const start = prev.next!;
let curr: ListNode | null = start;
let p: ListNode | null = null;
for (let i = 0; i <= n - m; i++) {
const next = curr!.next;
curr!.next = p;
p = curr;
curr = next;
}
prev.next = p;
start.next = curr;
return dummy.next;
}- Time: O(n), Space: O(1).
Example 3: Reverse Nodes in K-Group
Problem: Reverse every k consecutive nodes. If the number of nodes is not a multiple of k, leave the remainder unchanged.
Use a dummy head. Repeatedly: check if there are k nodes left, reverse that segment (same in-place pattern), then move the "tail" pointer past the reversed segment.
function reverseKGroup(head: ListNode | null, k: number): ListNode | null {
const dummy = new ListNode(-1);
dummy.next = head;
let tail = dummy;
while (true) {
let count = 0;
let curr: ListNode | null = tail.next;
while (curr !== null && count < k) {
curr = curr.next;
count++;
}
if (count !== k) break;
const groupHead = tail.next!;
let prev: ListNode | null = tail;
curr = tail.next;
for (let i = 0; i < k; i++) {
const next = curr!.next;
curr!.next = prev;
prev = curr;
curr = next;
}
tail.next = prev;
groupHead.next = curr;
tail = groupHead;
}
return dummy.next;
}- Time: O(n), Space: O(1).
Example 4: Reverse Only the Second Half (for Palindrome / Reorder)
Problem: Given you have a pointer to the middle node (or the start of the second half), reverse from that node to the end.
Same in-place loop: prev = null, curr = middleNode, then while curr: next = curr.next, curr.next = prev, prev = curr, curr = next. Return prev as the new head of the reversed second half.
Edge Cases
- Empty list β head is null; return null. The loop never runs, prev stays null.
- Single node β one iteration: next is null, curr.next = prev (null), prev = curr, curr = null. Return prev (the single node).
- Sublist at head β m = 1; use a dummy so "prev" exists before the segment.
- Sublist at tail β n = length; the "suffix" is null; start.next = null is correct.
Common Mistakes
- Losing the rest of the list β Always save
next = curr.nextbefore changingcurr.next. - Wrong initial prev β For full reverse, prev must start as null so the new tail's next is null.
- Returning head β After reverse, the original head is the new tail; return
prev(the new head). - Reconnecting sublist β After reversing a segment, wire the node before the segment to the new segment head, and the old segment head (now tail) to the node after the segment.
Time and Space Complexity
- Time: O(n) for one pass (or O(n) total for k-group with multiple segments).
- Space: O(1) β only a fixed number of pointers.
Summary
- In-place reverse: prev = null; for each node: save next, point curr to prev, advance prev and curr; return prev.
- Use for full reverse, reverse between mβn, reverse in k-group, and as a building block in Palindrome Linked List and Reorder List.
See also Fast and Slow Pointers (to find the middle before reversing) and Reverse Nodes in K-Group.