DSA Patterns: Linked Lists

LilSardarXLilSardarX
11 min read

πŸ“Œ TL;DR

This blog is a deep dive into the most important patterns and templates used in Linked List problems β€” the kind that show up over and over again in coding interviews.

You’ll walk away with:

  • πŸ“¦ 7 essential Linked List patterns, each tied to a real Leetcode problem
  • 🧠 Clean, reusable Java templates for each pattern
  • πŸ§ͺ Detailed dry runs for every problem so you can visualize pointer movement
  • ⚠️ High-ROI interview insights to avoid common Linked List bugs

βœ… If you’re short on time, focus on the sections:
Must-Know Patterns, Templates, and Dry Runs
Interview Insights

Introduction

Linked Lists are where pointers shine. Unlike arrays, they don’t give you direct access by index β€” instead, you have to traverse and manipulate the structure node by node.

This pattern teaches you how to:

  • Traverse, reverse, merge, and manipulate nodes
  • Use fast/slow pointers for elegant solutions
  • Spot cycles, detect intersections, and work with complex structures

πŸ“Œ When to Use Linked List Patterns

Reach for these techniques when:

  • You’re working with ListNode objects (custom linked lists)
  • You're told O(1) insertion/deletion is required
  • You need to reverse or reorder a structure
  • You’re asked to detect cycles, intersection, or midpoints
  • You see two-pointer behavior on nodes

🧠 Core Techniques

TechniqueDescription
Dummy NodeSimplifies edge cases like head deletion
Fast & Slow PointersDetect cycles, find midpoint
ReversalReverse list in-place (iterative/recursive)
Length DifferenceHandle intersecting linked lists
Splitting/MergingDivide and recombine nodes smartly
HashMapTrack random pointers or seen nodes

πŸ§ͺ Problem Walkthroughs

These are the most commonly asked Linked List problems that map to core patterns:

ProblemPattern (Jump ↓)Brief
Reverse a Linked List (#206)ReversalFlip node pointers
Linked List Cycle (#141)Fast & slow pointersDetect loop
Remove N-th Node From End (#19)Two pointersOffset logic
Merge Two Sorted Lists (#21)Merge + dummy nodeCombine in order
Detect Cycle II (#142)Cycle start logicFloyd’s Algorithm
Reorder List (#143)Midpoint + reverseInterleaved layout
Copy List with Random Pointer (#138)HashMap/interleavingDeep copy with randoms

Must-Know Patterns, Templates, and Dry Runs

πŸ”Ή Pattern: Reversal

Used in: Leetcode #206 – "Reverse a Linked List"

Goal: Reverse the direction of a singly linked list, in-place.

Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ null

Output: 4 β†’ 3 β†’ 2 β†’ 1 β†’ null


πŸ”Ή What we would do (High-Level)

  • Use 3 pointers: prev, curr, and next.
  • At each step:
    • Save curr.next in next
    • Point curr.next to prev
    • Move both prev and curr forward

πŸ”Ή Template

ListNode prev = null; 
ListNode curr = head; 

while (curr != null) { 
    ListNode next = curr.next; // Save next node 
    curr.next = prev;          // Reverse the link 
    prev = curr;               // Move prev ahead 
    curr = next;               // Move curr ahead 
} 
return prev; // New head of reversed list

πŸ”Ή Dry Run

Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ null

Stepcurrnext (saved)Actionprev becomesResult so far
1121.next β†’ null11
2232.next β†’ 122 β†’ 1
3343.next β†’ 233 β†’ 2 β†’ 1
44null4.next β†’ 344 β†’ 3 β†’ 2 β†’ 1 β†’ null βœ…

πŸ”Ή Pattern: Fast & Slow Pointers

Used in: Leetcode #141 – "Linked List Cycle"

Goal: Return true if a linked list contains a cycle (loop), false otherwise

Input: 3 β†’ 2 β†’ 0 β†’ -4 β†’ (points back to 2)

Output: true


πŸ”Ή What we would do (High-Level)

  • Use two pointers: slow and fast
  • Move slow by 1, fast by 2
  • If they meet β†’ cycle exists
  • If fast hits null β†’ no cycle

πŸ”Ή Template

ListNode slow = head, fast = head; 

while (fast != null && fast.next != null) { 
    slow = slow.next; 
    fast = fast.next.next; 

    if (slow == fast) return true; 
} 
return false;

πŸ”Ή Dry Run

Input: 3 β†’ 2 β†’ 0 β†’ -4 β†’ (back to 2)

StepslowfastAction
120move slow (1 step), fast (2 steps)
202fast is now looping
3-4-4βœ… fast == slow β†’ cycle detected

βœ… Output: true


πŸ”Ή Pattern: Two Pointers (Offset Technique)

Used in: Leetcode #19 – "Remove N-th Node From End of List"

Goal: Delete the N-th node from the end of a singly linked list

Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5, n = 2

Output: 1 β†’ 2 β†’ 3 β†’ 5


πŸ”Ή What we would do (High-Level)

  • Use a dummy node pointing to head (handles edge case)
  • Move fast pointer n steps ahead
  • Then move both fast and slow until fast.next == null
  • slow.next is the node to delete β†’ skip it

πŸ”Ή Template

ListNode dummy = new ListNode(0); 
dummy.next = head; 

ListNode fast = dummy; 
ListNode slow = dummy; 

// Move fast ahead by n steps 
for (int i = 0; i < n; i++) { 
    fast = fast.next; 
} 

// Move both until fast.next == null 
while (fast.next != null) { 
    fast = fast.next; 
    slow = slow.next; 
} 

// Skip the node 
slow.next = slow.next.next; 

return dummy.next;

πŸ”Ή Dry Run

Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5, n = 2

Step 1: Move fast ahead 2 steps

  • fast is at node 3

Step 2: Move both fast and slow

Stepfastslow
141
252
3null3

Now slow.next = 4 β€” we skip it β†’ 3.next = 5

βœ… Final Output: 1 β†’ 2 β†’ 3 β†’ 5

πŸ”Ή Pattern: Merge + Dummy Node

Used in: Leetcode #21 – "Merge Two Sorted Lists" Goal: Merge two sorted linked lists into one sorted linked list Input: l1 = 1 β†’ 3 β†’ 4, l2 = 1 β†’ 2 β†’ 4 Output: 1 β†’ 1 β†’ 2 β†’ 3 β†’ 4 β†’ 4


πŸ”Ή What we would do (High-Level)

  • Use a dummy node to simplify edge cases
  • Use a tail pointer to build the new list
  • At each step, compare values of l1 and l2
  • Attach the smaller node and move that list’s pointer forward

πŸ”Ή Template

ListNode dummy = new ListNode(0);
ListNode tail = dummy;

while (l1 != null && l2 != null) {
    if (l1.val < l2.val) {
        tail.next = l1;
        l1 = l1.next;
    } else {
        tail.next = l2;
        l2 = l2.next;
    }
    tail = tail.next;
}

tail.next = (l1 != null) ? l1 : l2;

return dummy.next;

πŸ”Ή Dry Run

Input: l1 = 1 β†’ 3 β†’ 4, l2 = 1 β†’ 2 β†’ 4

Stepl1l2ChosenResult so far
111l21
212l11 β†’ 1
332l21 β†’ 1 β†’ 2
434l11 β†’ 1 β†’ 2 β†’ 3
544l21 β†’ 1 β†’ 2 β†’ 3 β†’ 4
64nulll11 β†’ 1 β†’ 2 β†’ 3 β†’ 4 β†’ 4 βœ…

βœ… Output: 1 β†’ 1 β†’ 2 β†’ 3 β†’ 4 β†’ 4


πŸ”Ή Pattern: Cycle Start Logic

Used in: Leetcode #142 – "Linked List Cycle II" Goal: If a cycle exists, return the node where the cycle begins Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5 β†’ 6 β†’ (points back to 3) Output: Node with value 3


πŸ”Ή What we would do (High-Level)

  • Use fast/slow pointers to detect if a cycle exists
  • Once a meeting point is found, reset one pointer to head
  • Move both pointers one step at a time
  • The point where they meet again is the start of the cycle

πŸ”Ή Template

ListNode slow = head, fast = head;

// Step 1: Detect cycle
while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow == fast) break;
}

// No cycle
if (fast == null || fast.next == null) return null;

// Step 2: Find cycle start
slow = head;
while (slow != fast) {
    slow = slow.next;
    fast = fast.next;
}

return slow;

πŸ”Ή Dry Run

Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5 β†’ 6 β†’ (points back to 3)

  • slow and fast meet at node 5
  • reset slow to head
StepslowfastExplanation
115move both one step
226
333βœ… pointers meet again

βœ… Output: node with value 3


πŸ”Ή Pattern: Midpoint + Reverse + Merge

Used in: Leetcode #143 – "Reorder List" Goal: Rearrange list to: first β†’ last β†’ second β†’ second-last β†’ ... Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5 Output: 1 β†’ 5 β†’ 2 β†’ 4 β†’ 3


πŸ”Ή What we would do (High-Level)

  1. Use fast/slow to find middle
  2. Reverse second half
  3. Merge first and reversed second half

πŸ”Ή Template

// Step 1: Find middle
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
}

// Step 2: Reverse second half
ListNode second = reverse(slow.next);
slow.next = null;

// Step 3: Merge both halves
ListNode first = head;
while (second != null) {
    ListNode tmp1 = first.next;
    ListNode tmp2 = second.next;

    first.next = second;
    second.next = tmp1;

    first = tmp1;
    second = tmp2;
}

πŸ”Ή Dry Run

Input: 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5

  • Step 1: middle is 3
  • Step 2: reverse 4 β†’ 5 β†’ becomes 5 β†’ 4
  • Step 3: merge
StepfirstsecondActionResult
1151.next = 5, 5.next = 21 β†’ 5 β†’ 2
2242.next = 4, 4.next = 32 β†’ 4 β†’ 3

βœ… Final: 1 β†’ 5 β†’ 2 β†’ 4 β†’ 3


πŸ”Ή Pattern: HashMap / Interleaving Clone

Used in: Leetcode #138 – "Copy List with Random Pointer" Goal: Create a deep copy of a list with .next and .random pointers Input: A β†’ B β†’ C with arbitrary .random links Output: A' β†’ B' β†’ C' (deep copy, same structure)


πŸ”Ή What we would do (High-Level)

  1. Interleave original and copied nodes: A β†’ A' β†’ B β†’ B'...
  2. Assign random pointers to copied nodes
  3. Separate the two lists into original and cloned

πŸ”Ή Template

// Step 1: Interleave clone nodes
Node curr = head;
while (curr != null) {
    Node copy = new Node(curr.val);
    copy.next = curr.next;
    curr.next = copy;
    curr = copy.next;
}

// Step 2: Assign random pointers
curr = head;
while (curr != null) {
    if (curr.random != null)
        curr.next.random = curr.random.next;
    curr = curr.next.next;
}

// Step 3: Separate cloned list
curr = head;
Node pseudoHead = new Node(0), copyCurr = pseudoHead;
while (curr != null) {
    copyCurr.next = curr.next;
    curr.next = curr.next.next;
    curr = curr.next;
    copyCurr = copyCurr.next;
}

return pseudoHead.next;

πŸ”Ή Dry Run

Input: A β†’ B β†’ C with A.random β†’ C, B.random β†’ A, C.random β†’ B

  • Step 1: Interleave β†’ A β†’ A' β†’ B β†’ B' β†’ C β†’ C'
  • Step 2: Assign randoms using curr.random.next
  • Step 3: Detach clone list

βœ… Output: A' β†’ B' β†’ C' (deep copy with randoms)


Interview Insights

  • βœ… Use a dummy node when deleting or inserting near the head β€” it prevents null pointer bugs and simplifies code.
  • βœ… Always save next = curr.next before changing links β€” especially in reversal problems, to avoid losing the rest of the list.
  • βœ… Watch for null checks before accessing node.next β€” edge cases like single-node or empty lists often break code.
  • βœ… Set .next = null when splitting or reversing β€” failing to break the link can cause accidental cycles or infinite loops.
  • βœ… Use .val, not node references, when comparing linked list values β€” useful in problems like Palindrome LL.

This should help cover most of what's important to know about Linked Lists from an interview perspective.

0
Subscribe to my newsletter

Read articles from LilSardarX directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

LilSardarX
LilSardarX

I’m figuring things out in tech β€” and blogging along the way. I write what I learn, so I can revise it later and maybe help you avoid a few rabbit holes.