Skip to content
ΣDSA Patterns
Menu
Language

Pattern #31

Linked List Manipulation

Essential

Reversal, in-place merge, dummy head, splice, and partition.

When to use

Use when restructuring a linked list in place: reverse, merge, splice, partition, or rotate. Distinct from fast-slow (which detects cycles/midpoints).

Recognition cues

  • Reverse / merge / partition a linked list
  • Rearrange nodes in place (no new list)
  • Dummy head to simplify edge cases at the head
  • Group swap / rotate / k-group

Common pitfalls

  • Losing the next pointer before reassigning (draw it)
  • Forgetting a dummy head for edge cases at the head
  • Creating a cycle by not nulling the last next

90-second recognition drill

Which pattern fits best?

  • Reverse / merge / partition a linked list
  • Rearrange nodes in place (no new list)
  • Dummy head to simplify edge cases at the head

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 8
1
2
3
4
5

prev = null, cur = head

Reverse 1→2→3→4→5 in place. Cardinal rule: save next before you overwrite it.

How to think about it

Linked list manipulation is pointer rewiring. You rarely allocate new nodes; you reassign next pointers to reorder existing ones. The cardinal rule: before you overwrite a next, save the old value so you do not lose the rest of the list. Draw the pointer diagram for every step, off-by-one here is a silent corruption, not a crash.

A dummy head (sentinel) is the single most useful habit. By pointing dummy.next at the real head, you eliminate the “delete / insert at head” special case: every operation becomes a “previous-node” operation, and the new head is always dummy.next.

Template shapes

Shape Core move Example
Reverse whole prev, cur, nxt triple LC 206
Reverse range [a, b) Reverse until cur === b LC 92, LC 25 (k-group)
Merge two sorted Dummy + compare heads LC 21
Partition / group nodes Two dummy tails (left/right), link at end LC 328

Complexity baseline

O(n) time, O(1) extra space (a handful of pointers). The whole point: avoid copying the list. If you allocate a new list you are doing it the slow way.

From template to problem

  1. Identify the operation: reverse, merge, splice, partition, or a combination.
  2. Decide where the new head will be - and protect it with a dummy if it can change.
  3. Save next before rewriting; null the final next to avoid cycles.
  4. Return dummy.next (or the captured new head), never a stale head reference.

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Linked List Manipulation · Template
/** Linked list manipulation template: reverse + merge with dummy head. */
export class ListNode {
  val: number;
  next: ListNode | null;
  constructor(val = 0, next: ListNode | null = null) {
    this.val = val; this.next = next;
  }
}

export function reverseList(head: ListNode | null): ListNode | null {
  let prev: ListNode | null = null;
  let cur = head;
  while (cur) {
    const nxt = cur.next;
    cur.next = prev;
    prev = cur;
    cur = nxt;
  }
  return prev;
}

export function mergeTwoLists(a: ListNode | null, b: ListNode | null): ListNode | null {
  const dummy = new ListNode();
  let tail = dummy;
  while (a && b) {
    if (a.val <= b.val) { tail.next = a; a = a.next; }
    else { tail.next = b; b = b.next; }
    tail = tail.next;
  }
  tail.next = a ?? b;
  return dummy.next;
}
/** Linked list manipulation template: reverse + merge with dummy head. */
export class ListNode {
  val: number;
  next: ListNode | null;
  constructor(val = 0, next: ListNode | null = null) {
    this.val = val; this.next = next;
  }
}

export function reverseList(head: ListNode | null): ListNode | null {
  let prev: ListNode | null = null;
  let cur = head;
  while (cur) {
    const nxt = cur.next;
    cur.next = prev;
    prev = cur;
    cur = nxt;
  }
  return prev;
}

export function mergeTwoLists(a: ListNode | null, b: ListNode | null): ListNode | null {
  const dummy = new ListNode();
  let tail = dummy;
  while (a && b) {
    if (a.val <= b.val) { tail.next = a; a = a.next; }
    else { tail.next = b; b = b.next; }
    tail = tail.next;
  }
  tail.next = a ?? b;
  return dummy.next;
}
#StatusProblemTypeDone
  1. 1#21 Merge Two Sorted ListsGuide
  2. 2#24 Swap Nodes in PairsGuide
  3. 3#25 Reverse Nodes in k-GroupGuide
  4. 4#92 Reverse Linked List IIGuide
  5. 5#206 Reverse Linked ListGuide
  6. 6#328 Odd Even Linked ListGuide