Linked Lists Explained (for Coding Interviews)
A linked list is a chain of nodes, each holding a value and a pointer to the next. Here's how linked lists work, singly vs doubly, and the classic interview problems — reverse, detect a cycle, find the middle.
A linked list is a chain of nodes, where each node holds a value and a pointer to the next node. Instead of sitting in one contiguous block like an array, the nodes are scattered in memory and strung together by pointers — you start at the head and follow the chain.
Linked lists are an interview favourite not because they’re used everywhere in practice, but because they test something pure: can you manipulate pointers carefully without losing the chain? Get the handful of classic problems down and this whole topic is yours.
How a linked list is built
Each node is a tiny object: a value plus a next reference.
class Node {
constructor(value) {
this.value = value;
this.next = null; // points to the next node, or null at the end
}
}
// 1 → 2 → 3 → null
const head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
You only hold the head. To reach the third node you walk: head.next.next. There’s no list[2] — that’s the core trade-off.
Singly vs doubly linked
- Singly linked: each node points only to
next. Lightweight, one-directional. - Doubly linked: each node also points to
prev, so you can walk backward and delete a node in O(1) given a reference to it. Costs extra memory per node.
Linked list vs array
| Array | Linked list | |
|---|---|---|
| Access by index | O(1) | O(n) |
| Insert/delete at front | O(n) | O(1) |
| Insert/delete in middle | O(n) | O(1)* |
| Memory | contiguous | scattered + pointer overhead |
*O(1) once you already hold the node before it.
Use a linked list when you insert and remove at the ends constantly and rarely need random access — otherwise an array (or dynamic array) is usually better in practice due to cache locality.
Traversing the list
The fundamental loop — walk until you hit null:
let current = head;
while (current !== null) {
console.log(current.value);
current = current.next; // step forward
}
The classic interview problems
Almost every linked-list interview is a variation on four problems. Learn these and you’re covered.
Reverse a linked list
The most-asked one. Walk through, flipping each next pointer backward, tracking three pointers:
function reverse(head) {
let prev = null;
let current = head;
while (current !== null) {
const next = current.next; // save the rest
current.next = prev; // flip the pointer
prev = current; // advance
current = next;
}
return prev; // new head
}
O(n) time, O(1) space. The trick is saving next before you overwrite current.next.
Detect a cycle (fast & slow pointers)
Does the list loop back on itself? Floyd’s algorithm uses two pointers at different speeds — the two-pointer technique applied to lists:
function hasCycle(head) {
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next; // 1 step
fast = fast.next.next; // 2 steps
if (slow === fast) return true; // they met → cycle
}
return false;
}
If there’s a loop, the fast pointer laps the slow one and they collide. O(n) time, O(1) space.
Find the middle node
Same fast/slow idea: when fast reaches the end, slow is at the middle.
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
// slow is now the middle
Merge two sorted lists
Use a dummy node to simplify the head handling, then stitch the smaller node each step. The dummy-node trick removes the annoying “is this the first node?” special case.
Common mistakes
- Losing the rest of the list. Overwrite
current.nextbefore saving it and everything after is gone. Savenextfirst. - Null-pointer errors. Always check
current(andfast.next) before dereferencing — the end of the list isnull. - Forgetting the dummy node, then wrestling with head edge cases.
- Off-by-one with fast/slow — decide up front whether you want the exact middle or the first-of-two middles.
current.next = prev before saving current.next permanently severs the rest of the list. The order is always: save next → rewire → advance. Draw the pointers on paper if you're unsure.
Where this fits
Linked lists are part of Phase 2 of the coding interview roadmap, and they pair tightly with the two-pointer technique and the broader data structures overview.
The pointer-manipulation patterns are drawn out as diagrams in our job-ready tier — JavaScript in Three Months, Python in Three Months, and Java in Three Months. For the harder variants (LRU cache with a doubly linked list, copy-with-random-pointer) that show up in senior interviews, the for Staff Engineers tier goes deeper: JavaScript, Python, Java.
Draw the pointers, save before you rewire, and linked-list problems become mechanical.
Frequently asked questions
What is a linked list?
A linked list is a linear data structure made of nodes, where each node holds a value and a pointer (reference) to the next node. Unlike an array, the nodes are not stored contiguously in memory — they are connected by pointers, so you follow the chain from the head node onward.
What is the difference between an array and a linked list?
An array stores elements contiguously, giving O(1) access by index but O(n) insertion or deletion in the middle (elements must shift). A linked list stores nodes connected by pointers, giving O(1) insertion or deletion when you have the node, but O(n) access by position because you must walk from the head.
How do you detect a cycle in a linked list?
Use Floyd's cycle-detection algorithm (the tortoise and hare): move one pointer one step at a time and another two steps at a time. If they ever meet, there is a cycle; if the fast pointer reaches the end (null), there is none. It runs in O(n) time and O(1) space.
How do you reverse a linked list?
Iterate through the list keeping three pointers — previous, current, and next. For each node, save next, point current.next back to previous, then advance previous and current. When current becomes null, previous is the new head. It is O(n) time and O(1) space.