๐Ÿณ IntuitiveFE
Login
โ† All concepts

Linked List

โฑ๏ธ ~4-minute bite ยท solve the sandbox to master

0%lesson
๐Ÿง’

5-Year-Old Metaphor

โ€” The physical, real-world picture. No jargon.

๐Ÿš‚ A train where each car knows only the car directly behind it โ€” to reverse the train, uncouple and recouple one car at a time.

What a linked list is

An array stores everything in a contiguous block of memory โ€” each element lives at a fixed offset. A linked list is different: each node can live anywhere in memory. The only connection is that each node holds a pointer (a memory address) to the next node.

Node { value: 1, next: โ†’ Node {value: 2, next: โ†’ Node {value: 3, next: null} } }
Each node: two fields. That's it.

Linked list wins

  • Insert/delete at head: O(1) โ€” just rewire one pointer
  • Insert in middle (with pointer): O(1)
  • No pre-allocated size โ€” grows on demand
  • Efficient as a queue, stack, or deque backbone

Linked list loses

  • Random access: O(n) โ€” must walk from head
  • No binary search (no index)
  • Extra memory per node (the pointer itself)
  • Poor cache locality โ€” nodes scattered in memory

The reversal intuition (the #1 interview operation)

Each car of our train knows only the car in front of it (its next pointer). To reverse the train, you walk car by car and flip each car's coupler to point backward instead of forward. You need a "spare coupler" (the prev variable) to remember where to point it, and you must save the next car's address before you cut the forward coupler.

Three variables. One pass. O(n) time, O(1) space. No extra list needed.

Singly vs Doubly linked list

Singly: prev โ† [val | nextโ†’] โ†’ next (one pointer per node)
Doubly: โ† [prev | val | next] โ†’ (two pointers โ€” can walk both ways)

A doubly linked list makes delete-in-place O(1) without needing a separate "find the predecessor" pass. LRU Cache (the eviction algorithm) is a doubly linked list + hashmap.

๐ŸŽ›๏ธ

Interactive Sandbox

โ€” Move something, see it react instantly.
How to use: Step through the reversal one frame at a time. Watch arrows flip as curr advances and prev trails behind. The โœ• means the forward link has been severed.
null
ยท
1
curr
โ†’
2
next
โ†’
3
ยท
โ†’
4
ยท
โ†’
5
ยท
โ†’
null
ยท
โ— prevโ— currโ— nextโ† reversed arrowโœ• severed link

null

prev

node 1

curr

1 / 6

step

[INIT]Initial: prev=null, curr=head (node 1). About to save curr.next as 'next'.
๐ŸŽฏ

Challenge

Step through to complete the linked list reversal [1โ†’2โ†’3โ†’4โ†’5] โ†’ [5โ†’4โ†’3โ†’2โ†’1].

Try it
๐ŸŽฏ

Why Should I Care?

โ€” The exact interview question + the bug it kills.

Exact interview question โ€” reverse a linked list

"Reverse a singly linked list in-place. O(n) time, O(1) space."

ts
1interface ListNode {
2 val: number;
3 next: ListNode | null;
4}
5ย 
6function reverseList(head: ListNode | null): ListNode | null {
7 let prev: ListNode | null = null;
8 let curr = head;
9 while (curr !== null) {
10 const next = curr.next; // 1. save next
11 curr.next = prev; // 2. flip arrow
12 prev = curr; // 3. advance prev
13 curr = next; // 4. advance curr
14 }
15 return prev; // new head
16}
17// Time: O(n) Space: O(1)

Classic follow-up โ€” detect a cycle (Floyd's algorithm)

"Given a linked list, return true if it contains a cycle."

ts
1function hasCycle(head: ListNode | null): boolean {
2 let slow = head;
3 let fast = head;
4 while (fast !== null && fast.next !== null) {
5 slow = slow!.next; // 1 step
6 fast = fast.next.next; // 2 steps
7 if (slow === fast) return true; // caught!
8 }
9 return false;
10}
11// If there's a cycle: fast laps slow, they meet.
12// If no cycle: fast hits null first.
13// Time: O(n) Space: O(1)

Senior follow-up โ€” merge two sorted lists

js
1function mergeTwoLists(
2 l1: ListNode | null,
3 l2: ListNode | null,
4): ListNode | null {
5 const dummy = { val: 0, next: null } as ListNode;
6 let cur = dummy;
7 while (l1 && l2) {
8 if (l1.val <= l2.val) { cur.next = l1; l1 = l1.next; }
9 else { cur.next = l2; l2 = l2.next; }
10 cur = cur.next!;
11 }
12 cur.next = l1 ?? l2; // attach the remaining tail
13 return dummy.next;
14}
15// Dummy head trick: avoids special-casing an empty result.
16// Time: O(n+m) Space: O(1)

Complexity comparison: linked list vs array

OperationArrayLinked List
Access by indexO(1)O(n)
SearchO(n)O(n)
Insert at headO(n) shiftO(1)
Insert at tailO(1) amort.O(n) or O(1)*
Insert in middleO(n) shiftO(1) w/ pointer
Delete at headO(n) shiftO(1)

* O(1) insert at tail requires keeping a tail pointer. Common in queue implementations.

๐Ÿ”ฌ

The Deep Dive

โ€” Spec refs, engine internals, the minutiae.

The dummy-head pattern โ€” simplifies every linked list problem

Most linked list bugs involve special-casing the head node. A dummy head (a sentinel node before the real list) eliminates these cases: you can always do cur.next = someNode without checking "is this the first node?".

ts
1// Without dummy โ€” must handle head separately
2function removeNthFromEnd(head: ListNode, n: number): ListNode | null {
3 // ... complicated head-removal check
4ย 
5// With dummy โ€” uniform handling
6function removeNthFromEnd(head: ListNode, n: number): ListNode | null {
7 const dummy = { val: 0, next: head } as ListNode;
8 let fast: ListNode | null = dummy;
9 let slow: ListNode | null = dummy;
10 for (let i = 0; i <= n; i++) fast = fast!.next; // n+1 ahead
11 while (fast !== null) { fast = fast.next; slow = slow!.next; }
12 slow!.next = slow!.next!.next; // remove target
13 return dummy.next;
14}

Recursive reversal โ€” why you should know it but not use it

js
1function reverseListRec(head: ListNode | null): ListNode | null {
2 if (!head || !head.next) return head; // base: 0 or 1 node
3 const newHead = reverseListRec(head.next); // recurse to end
4 head.next.next = head; // flip: next node points back at head
5 head.next = null; // sever head's forward pointer
6 return newHead;
7}
8// Time: O(n) Space: O(n) โ† call stack depth!

Recursive reversal is elegant but uses O(n) stack space. For a list of 100,000 nodes you'd blow the call stack. Interviewers often ask: "can you do this iteratively?" โ€” the iterative version (O(1) space) is almost always preferred.

Fast & slow pointer โ€” the general pattern

Floyd's cycle detection is one instance of a broader pattern: two pointers moving at different speeds to find a structural property without extra memory.

  • Find middle: when fast reaches the end, slow is at the middle. Useful for "reverse second half" problems.
  • Find cycle entry: after detection, reset one pointer to head and advance both at speed 1 โ€” they meet at the cycle entrance.
  • Find Nth from end: advance fast N steps, then move both until fast hits null.

When does a linked list appear in production code?

  • LRU Cache โ€” doubly linked list + hashmap. The list maintains access order; the map gives O(1) lookup. Every get/put is O(1).
  • Browser history โ€” doubly linked list. Back/forward navigation is O(1) pointer hops.
  • Undo/redo stacks โ€” singly linked list where each node stores a delta or snapshot.
  • React Fiber โ€” the reconciler internally uses a linked work-unit tree (each fiber is a node with child, sibling, return pointers).

Common implementation bugs

  • Forgetting to save next before flipping: the most common reversal bug. After curr.next = prev, the original next is gone unless you saved it first.
  • Off-by-one on "Nth from end": count carefully whether N is 1-indexed or 0-indexed. Test with a 1-node list and N=1.
  • Not handling null / single-node input: every linked list function should handle head === null as its first check.
๐ŸŽค

Interview Questions

โ€” Real questions from real interviews โ€” with answers.

prev, curr, next โ€” you need 'next' to save the forward link before flipping curr.next.

If a cycle exists, fast gains 1 step per round on slow โ€” they must eventually collide.

A sentinel node before the list's head eliminates head-insertion/deletion special cases.

Fast/slow pointers: when fast reaches the end, slow is at the middle.

Hashmap (O(1) lookup) + doubly linked list (O(1) reorder) โ€” the two structures together give O(1) get and put.

๐ŸŽฎ

Memory Game

โ€” Quick quiz โ€” lock the concept in long-term memory.
1/4

In Floyd's algorithm, if the list has no cycle, what happens to the fast pointer?