DSA Patterns: Linked Lists

Table of contents
- π TL;DR
- Introduction
- π When to Use Linked List Patterns
- π§ Core Techniques
- π§ͺ Problem Walkthroughs
- Must-Know Patterns, Templates, and Dry Runs
- πΉ Pattern: Reversal
- πΉ Pattern: Fast & Slow Pointers
- πΉ Pattern: Two Pointers (Offset Technique)
- πΉ Pattern: Merge + Dummy Node
- πΉ Pattern: Cycle Start Logic
- πΉ Pattern: Midpoint + Reverse + Merge
- πΉ Pattern: HashMap / Interleaving Clone
- Interview Insights
π 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
Technique | Description |
Dummy Node | Simplifies edge cases like head deletion |
Fast & Slow Pointers | Detect cycles, find midpoint |
Reversal | Reverse list in-place (iterative/recursive) |
Length Difference | Handle intersecting linked lists |
Splitting/Merging | Divide and recombine nodes smartly |
HashMap | Track random pointers or seen nodes |
π§ͺ Problem Walkthroughs
These are the most commonly asked Linked List problems that map to core patterns:
Problem | Pattern (Jump β) | Brief |
Reverse a Linked List (#206) | Reversal | Flip node pointers |
Linked List Cycle (#141) | Fast & slow pointers | Detect loop |
Remove N-th Node From End (#19) | Two pointers | Offset logic |
Merge Two Sorted Lists (#21) | Merge + dummy node | Combine in order |
Detect Cycle II (#142) | Cycle start logic | Floydβs Algorithm |
Reorder List (#143) | Midpoint + reverse | Interleaved layout |
Copy List with Random Pointer (#138) | HashMap/interleaving | Deep 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
, andnext
. - At each step:
- Save
curr.next
innext
- Point
curr.next
toprev
- Move both
prev
andcurr
forward
- Save
πΉ 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
Step | curr | next (saved) | Action | prev becomes | Result so far |
1 | 1 | 2 | 1.next β null | 1 | 1 |
2 | 2 | 3 | 2.next β 1 | 2 | 2 β 1 |
3 | 3 | 4 | 3.next β 2 | 3 | 3 β 2 β 1 |
4 | 4 | null | 4.next β 3 | 4 | 4 β 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
andfast
- 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)
Step | slow | fast | Action |
1 | 2 | 0 | move slow (1 step), fast (2 steps) |
2 | 0 | 2 | fast 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
pointern
steps ahead - Then move both
fast
andslow
untilfast.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
Step | fast | slow |
1 | 4 | 1 |
2 | 5 | 2 |
3 | null | 3 |
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
andl2
- 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
Step | l1 | l2 | Chosen | Result so far |
1 | 1 | 1 | l2 | 1 |
2 | 1 | 2 | l1 | 1 β 1 |
3 | 3 | 2 | l2 | 1 β 1 β 2 |
4 | 3 | 4 | l1 | 1 β 1 β 2 β 3 |
5 | 4 | 4 | l2 | 1 β 1 β 2 β 3 β 4 |
6 | 4 | null | l1 | 1 β 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
Step | slow | fast | Explanation |
1 | 1 | 5 | move both one step |
2 | 2 | 6 | |
3 | 3 | 3 | β 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)
- Use fast/slow to find middle
- Reverse second half
- 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
Step | first | second | Action | Result |
1 | 1 | 5 | 1.next = 5, 5.next = 2 | 1 β 5 β 2 |
2 | 2 | 4 | 2.next = 4, 4.next = 3 | 2 β 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)
- Interleave original and copied nodes: A β A' β B β B'...
- Assign random pointers to copied nodes
- 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.
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.