Intersection of Two Linked Lists
Two pointers walk their own lists, then switch to the other list when they hit the end. After at most (lenA + lenB) steps both pointers have covered equal total distance — they meet at the intersection node, or both arrive at null if no intersection exists. O(n + m) time, O(1) space, zero length calculation.
Table of contents
Before we start
Two lists share a suffix — a common tail. How do you find where they join? The obvious approach computes lengths, aligns the longer list, then walks both forward together. The elegant approach uses two pointers that automatically align themselves by switching lists — no length computation, no alignment step, just two pointers converging. By the end you will be able to:
- Explain why switching to the other list guarantees equal total distance.
- Write the solution in six lines from memory.
- Distinguish it from the cycle-detection approach (which also works but uses O(n) space or pointer modification).
Picture this first (no code yet)
A real-life story
Two hikers start at different trailheads on a mountain. Both trails merge into a single shared path before reaching the summit. The trails are different lengths before the merge point.
Hiker A reaches the merge point first — but instead of waiting, she immediately continues onto Hiker B's original trailhead and starts walking B's trail. Hiker B does the same: reaches the merge, continues onto A's trailhead, walks A's trail.
Now both hikers have walked exactly the same total distance: (A's trail) + (B's trail). The moment they are on the same trail — after the crossover — they are walking in sync. They arrive at the merge point at the exact same step.
That is the intersection algorithm. No stopwatch. No measuring trails in advance. Just walk, switch, walk again — meet at the join.
First, the slow way (so you feel the pain)
Compute the length of both lists. Advance the pointer on the longer list by the difference. Then walk both forward until they point to the same node.
def getIntersectionNode_slow(headA, headB):
lenA = lenB = 0
a, b = headA, headB
while a: lenA += 1; a = a.next
while b: lenB += 1; b = b.next
a, b = headA, headB
if lenA > lenB:
for _ in range(lenA - lenB): a = a.next
else:
for _ in range(lenB - lenA): b = b.next
while a and b:
if a is b: return a
a = a.next; b = b.next
return None
Three passes over the lists. Correct — but wordy. The pointer-switching approach does the same in two passes with six lines.
The turning point
Pause & think
List A has 5 nodes before the intersection. List B has 3 nodes before the intersection. Both share 2 nodes after the intersection.
Pointer A walks: 5 + 2 nodes on A, then when it hits null, switches and walks B's 3 nodes before the intersection — total from B's head to intersection: 3. Total distance for A = 5 + 2 + 3 = 10.
Pointer B walks: 3 + 2 nodes on B, then switches to A's 5 nodes before intersection. Total distance for B = 3 + 2 + 5 = 10.
Same total. After the switch, when they are both on the same list walking toward the intersection — they are in sync. They arrive at the intersection together.
The one idea to remember
The entire pattern in one sentence
Each pointer walks its own list then the other list — equal total distance (lenA + lenB) — so after the switch they are perfectly aligned and meet at the intersection node, or both land on null simultaneously if no intersection exists.
The code, line by line
def getIntersectionNode(headA, headB):
a, b = headA, headB
while a is not b:
a = a.next if a else headB # if A exhausted, switch to head of B
b = b.next if b else headA # if B exhausted, switch to head of A
return a # either the intersection node, or None (both exhausted together)
Six lines (two of them just the function signature and return). Read each:
a = a.next if a else headB— advance A; if A just ran off its end (a is None), reset to the head of B. This is the "switch" moment.while a is not b:— keep walking until both pointers are on the same object. If no intersection exists, both become None at the same step (after walking A_len + B_len total distance) —None is None→ True → loop exits → return None.return a— if there is an intersection,a is bat that node; return it. If not, both are None; return None.
Watch it happen, frame by frame
List A: 4 → 1 → 8 → 4 → 5 (intersection at node 8)
List B: 5 → 6 → 1 → 8 → 4 → 5
Labeling nodes:
- A-only: A4, A1
- B-only: B5, B6, B1
- Shared tail: X8, X4, X5
lenA (before X8) = 2, lenB (before X8) = 3
a starts at A4, b starts at B5
a: A4 → A1 → X8 → X4 → X5 → None → B5 → B6 → B1 → X8
b: B5 → B6 → B1 → X8 → X4 → X5 → None → A4 → A1 → X8
After switching (a went through None first):
Both reach X8 at step 9 (0-indexed). a is X8, b is X8.
a is b → True → exit loop. Return X8 ✅
No intersection: List A = 2 → 6 → 4, List B = 1 → 5
a: 2 → 6 → 4 → None → 1 → 5 → None
b: 1 → 5 → None → 2 → 6 → 4 → None
Both reach None at step 5. None is None → exit. Return None ✅
Why a is not b works for the "no intersection" case
When there is no intersection, after walking lenA + lenB total steps:
ahas walked all of A (lenA steps), then all of B (lenB steps), landing onNone.bhas walked all of B (lenB steps), then all of A (lenA steps), landing onNone.
None is None is True in Python — the while condition a is not b becomes False and the loop exits. return a returns None. Correct, no crash, no special case needed.
Common traps
Watch out for these
- Using
a != binstead ofa is not b. For linked list nodes,!=compares values if__eq__is defined. Two different nodes with the same value would falsely appear "equal." Always useis/is notfor object identity comparisons on linked list nodes. - Setting
a = headBwhen a is None, but forgetting b does the same. Both pointers must switch — not just one. If only A switches, the total distances are asymmetric and the meeting is not guaranteed. - Infinite loop if pointers never meet. This cannot happen if the implementation is correct — after at most lenA + lenB steps, both are at None (no intersection) or at the same intersection node. But if you accidentally do
a = headA(switch back to own list) instead ofa = headB(switch to other list), the loop never terminates.
Remember this forever
Intersection of Two Lists — 2 switching pointers
a, b = headA, headB
while a is not b:
a = a.next if a else headB
b = b.next if b else headA
return a
Why it works: total distance for both = lenA + lenB. After one switch each, they are in sync — they meet at the intersection (or both hit None if no intersection).
Trap: use is not, not !=. Both pointers must switch (not just one).
Check yourself
Why do both pointers walk exactly lenA + lenB steps before meeting (or both hitting None)?
Pointer A walks lenA nodes on list A, hits None, switches to list B's head, then walks lenB nodes on list B — if they meet at the intersection, it's after walking (lenA - shared) + shared + (lenB - shared) = lenA + lenB - shared steps...
Actually, the cleaner framing: Pointer A walks the non-shared part of A (call it a), then the shared part (s), then the non-shared part of B (b). Total: a + s + b. Pointer B walks the non-shared part of B (b), then shared (s), then non-shared part of A (a). Total: b + s + a. Same total. Both pointers arrive at the shared start (the intersection) after exactly (a + b) steps from the switch. Before the switch, they were out of sync — after the switch, they are perfectly aligned.
Can you solve this problem using a hash set? What are the tradeoffs?
Yes: traverse list A and add all nodes to a set. Traverse list B and check each node against the set — the first hit is the intersection. O(n + m) time, O(n) space for the set. The two-pointer approach is O(n + m) time, O(1) space — superior when memory is constrained. The hash set approach is simpler to reason about and fine for most real-world code; the two-pointer approach is the expected "optimal" interview answer.
Practice problems
| Problem | Difficulty | What to notice | Link |
|---|---|---|---|
| Intersection of Two Linked Lists | Easy | Switch on None; is not for identity | LC #160 |
| Linked List Cycle II | Medium | Floyd's algorithm for cycle entry — different problem, same "two pointer tricks" family | LC #142 |
Next up: Reorder List — the three-step pattern: find middle, reverse second half, merge the two halves alternately.