Algorithm

Intersection of Two Linked Lists

Two Pointer Pattern

Intersection of Two Linked Lists

Two singly linked lists may join at some node and share every node from there to the end (a Y shape). Given their heads, return the first shared node — the one where they merge — or null if they never meet. Matching is by node identity (the same node object), not by value; two different nodes that happen to hold equal values do not count as an intersection. The lists must be left unchanged, and the target is O(1) extra space.

CONSTRAINTS
  • 1 <= list lengths <= 10,000
  • Intersection is by node identity, not value
  • The original list structure must be preserved
  • Target: O(1) extra space
EXAMPLE 1
Input: listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], intersect at value 8
Output: Reference to the shared node 8
Both lists run down the same tail starting at that node; it is the first node they share by identity.
EXAMPLE 2
Input: listA = [2,6,4], listB = [1,5], no shared nodes
Output: null
The lists end in separate nodes and never merge, so there is no intersection.
Is the match by value or by the actual node?
By the actual node (identity). Two separate nodes with the same value are not an intersection.
What is returned when the lists never meet?
Null. With the two-pointer switch, both pointers reach the end together and the loop stops with them equal to null.
Can the lists have different lengths?
Yes — different prefix lengths are exactly the difficulty, and the switch (or the length-difference method) cancels that gap out.
Am I allowed to modify the lists?
No. The structure must be left intact, so approaches that relink nodes are off the table.

Two lists that intersect look like a Y: each has its own private prefix, and after the junction they run down the exact same shared tail. We want that junction node. The only thing that makes it awkward is that the two private prefixes can be different lengths, so two pointers walking forward from the two heads reach the junction at different times.

The straightforward tries

Compare every node of A against every node of B — O(N × M), too slow. Or put all of A's nodes into a hash set and scan B for the first one that's already in it — O(N + M) time but O(N) extra memory. Both work; we want to keep the time and drop the memory.

The idea: cancel out the extra prefix

Why don't two forward pointers meet on their own? Purely because one has a longer head start than the other before the junction. If we could remove that head-start difference, both pointers would be the same distance from the junction and would land on it together. One clean way: measure both lengths, advance the pointer on the longer list by the difference, then walk both in step until they point at the same node.

python
lenA, lenB = length(headA), length(headB)
a, b = headA, headB
for _ in range(lenA - lenB): a = a.next     # skip the longer list's extra prefix
for _ in range(lenB - lenA): b = b.next
while a is not b:
    a, b = a.next, b.next
return a                                     # the junction, or None if both hit the end
The neat trick that skips the measuring

There is a way to equalize the head starts without ever counting lengths. Walk pointer a through list A; when it falls off the end, send it to the head of B. Walk pointer b through list B; when it falls off the end, send it to the head of A. Now think about the total distance each travels to reach the junction. Let the private prefixes have lengths p and q, and the shared tail start at distance c from the junction on each. Pointer a travels p (its own list) then q (B's prefix) and arrives at the junction after p + q steps. Pointer b travels q then p — also p + q steps. Equal distances, so they land on the junction at the same moment. And if the lists never intersect, both pointers walk p + q steps and hit None together, ending the loop with the answer null. Either way it just works.

python
a, b = headA, headB
while a is not b:
    a = a.next if a else headB           # off the end of A → jump to B's head
    b = b.next if b else headA           # off the end of B → jump to A's head
return a
Crucial Noteon reaching the end, jump to the other list's head (not your own), and let the pointer visit None once before jumping — that single None step is what keeps the two path lengths exactly equal and lets the no-intersection case terminate instead of looping forever. Comparisons are by identity (is), because we want the same node, not merely an equal value.
Worked example:listA = 4 → 1 → 8 → 4 → 5, listB = 5 → 6 → 1 → 8 → 4 → 5
The shared tail starts at node 8. A's private prefix is [4, 1] (length 2); B's is [5, 6, 1] (length 3).
- a walks all 5 of A's nodes, hits the end, jumps to B's head. b walks all 6 of B's nodes, hits the end, jumps to A's head.
- After the switch, both have 3 more steps to the junction: a goes 5 → 6 → 1 → 8, b goes 4 → 1 → 8. Both reach node 8 after exactly 8 steps total. Return node 8.
Where this fits the family

Like Merge Two Sorted Lists, this is the multiple-sequence two-pointer shape — a pointer travelling each of two lists — but the clever part is different: here we equalize the two traversal lengths so pointers over unequal paths fall into sync. That "make both walks the same length so they meet" idea is the transferable trick; recognize it whenever two linked structures share a common suffix and you must find where they join using O(1) space. The brute force screams O(N × M); the fix is to stop re-scanning and instead line the two walks up so a single synchronized pass finds the meeting point.

Interactive Strategy Visualization

Phase 1: Initial Sweep

Strategy: Phase-Alignment Sweep

A0
A1
B0
B1
B2
B3
B4
I0
I1
I2
STARTING...
Explanation

Both pointers pA and pB start traversing. Notice that List A is much shorter than List B.

Pro Tip: Path Symmetry

Switching tracks ensures both pointers traverse exactly A + B nodes. This mathematical guarantee forces them to meet at the junction.

Time Complexity
O(N + M)

Total distance traversed is constant.

Space Complexity
O(1)

Two pointers, zero extra memory.

Core Trick
Track Switching

Neutralize depth differences.

O(N · M) Brute Force
O(N + M) Time · O(N) Space Hash Set
O(N + M) Time · O(1) Space Two-Pointer Switch