Intersection of Two Linked Lists (LC 160)
On this page
Pattern: Two Pointers / Length Equalization
Difficulty: Easy
Key Concept: Two walkers swap lists at the end so both travel the same total length and meet at the shared suffix (or both hit null).
Problem Statement
You are given the heads of two singly linked lists headA and headB. The lists may intersect at a node such that all nodes from that node to the end are shared (same object references, not merely equal values). Return the intersecting node, or null if they do not intersect.
Input: headA, headB (either may be null).
Output: The first shared ListNode, or null.
Notes: Intersection is defined by reference equality—the lists merge into one tail. There are no cycles.
1. Algorithm & Pseudocode
Brute force (HashSet of A’s nodes)
seen = empty set of ListNode
for p = headA; p != null; p = p.next:
add p to seen
for p = headB; p != null; p = p.next:
if seen contains p: return p
return null
Optimal (two pointers, switch lists at end)
pa = headA, pb = headB
while pa != pb:
pa = (pa == null) ? headB : pa.next
pb = (pb == null) ? headA : pb.next
return pa // intersection node or both null
Why it works (length math)
Let unique part of A have length a, unique part of B have length b, common tail length c.
Pointer on A walks a + c, then b after switch → a + c + b.
Pointer on B walks b + c, then a after switch → b + c + a.
Both totals equal a + b + c, so they align at the start of the common tail (or both null if no intersection and no shared tail).
2. Step-by-Step Analysis (Beginner-Friendly)
-
Reference vs value
The answer must be the same node object in both lists. In Java, use==between references, notequals()(unlessequalsis overridden to mean reference equality—whichObjectdoes by default, but==is clearer for “same node”). -
Why HashSet works
Store every address from list A, then walk B; the first node seen in the set is the merge point. Simple but O(n) memory. -
Why two pointers work
Without counting lengths explicitly, switching heads when a pointer hitsnullpads the shorter list with the longer list’s prefix, equalizing total steps—a compact mathematical trick. -
No intersection
Both traverse A then B (or B then A) and eventually both becomenullat the same time, sopa == pbwith valuenull. -
Beauty
Same idea works in C++/Python: pointer/reference traversal with swap. The insight is algebraic, not language-specific.
3. The Dry Run
Structure (shared suffix starts at node n8 with value 8):
- List A:
n4a → n1a → n8 → n4s → n5s - List B:
n5b → n6 → n1b → n8 → n4s → n5s
(n8, n4s, n5s are the same objects in both lists.)
| Step | pa |
pb |
Notes |
|---|---|---|---|
| 0 | n4a | n5b | |
| 1 | n1a | n6 | |
| 2 | n8 | n1b | |
| 3 | n4s | n8 | different nodes |
| 4 | n5s | n4s | |
| 5 | n5b | n5s | pa reached end of A → pa = headB; pb advanced to tail n5s |
| 6 | n6 | n4a | pa from n5b; pb reached end of B → pb = headA |
| 7 | n1b | n1a | |
| 8 | n8 | n8 | same reference — intersection |
Return n8 (value 8). This matches lists A = [4,1,8,4,5] and B = [5,6,1,8,4,5] merging at the first 8.
4. Java Solution
Brute Force
import java.util.HashSet;
import java.util.Set;
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> seen = new HashSet<>();
for (ListNode p = headA; p != null; p = p.next) {
seen.add(p);
}
for (ListNode p = headB; p != null; p = p.next) {
if (seen.contains(p)) {
return p;
}
}
return null;
}
}
Time: O(m + n). Space: O(m) for storing nodes of A (or O(max(m,n)) if you store the other list).
Optimal
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode pa = headA;
ListNode pb = headB;
while (pa != pb) {
pa = (pa == null) ? headB : pa.next;
pb = (pb == null) ? headA : pb.next;
}
return pa;
}
}
Time: O(m + n). Space: O(1).
5. The “Java vs. Others” Edge
- Use
==for nodes: You want reference identity—pa != pbandpa == nullare reference checks. This matches C pointer comparison for list nodes. - No special pointer syntax: Java references behave like tracked pointers; there is no
*/&, which can make the algorithm easier to read for beginners. - Math insight: Each pointer walks
a + b + csteps before meeting at the merge (or both walk off the end). Same formula whether implemented in Java, C++, or Python. HashSet<ListNode>: Uses reference identity forhashCode/equalsby default for object identity in the set (actuallyhashCodeis identity-based unless overridden—LeetCodeListNodeis typical). For clarity,seen.contains(p)still means “this exact node reference.”
6. Complexity Summary
| Approach | Time | Space | Notes |
|---|---|---|---|
| Brute Force | O(m + n) | O(m) | HashSet of one list’s nodes; very straightforward. |
| Optimal | O(m + n) | O(1) | Two pointers; switch to other head at end of path. |