To solve this, handle two scenarios: (A) both lists are acyclic — use length alignment; (B) lists may have cycles — detect cycle entries with Floyd's algorithm and handle combinations.python
class Node:
def __init__(self, val=0, nxt=None):
self.val = val
self.next = nxt
def detect_cycle_entry(head):
# Floyd's cycle detection. Returns entry node or None.
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
# find entry
ptr = head
while ptr is not slow:
ptr = ptr.next
slow = slow.next
return ptr
return None
def intersection_no_cycle(h1, h2):
# Align by length then walk together
def length(head):
n = 0
while head:
n += 1
head = head.next
return n
l1, l2 = length(h1), length(h2)
# advance longer
while l1 > l2:
h1 = h1.next; l1 -= 1
while l2 > l1:
h2 = h2.next; l2 -= 1
while h1 and h2:
if h1 is h2:
return h1
h1 = h1.next; h2 = h2.next
return None
def get_intersection(headA, headB):
e1 = detect_cycle_entry(headA)
e2 = detect_cycle_entry(headB)
if not e1 and not e2:
return intersection_no_cycle(headA, headB)
if (e1 and not e2) or (e2 and not e1):
# one cyclic, one acyclic -> cannot intersect by reference
return None
# both have cycles
if e1 is e2:
# shared entry: intersection might be before entry or at/after entry.
# Temporarily treat entry as end to find possible earlier intersection.
# Compute lengths up to entry
def dist_to_entry(head, entry):
d = 0
while head is not entry:
d += 1
head = head.next
return d
d1 = dist_to_entry(headA, e1)
d2 = dist_to_entry(headB, e1)
# align and scan until either meet or reach entry
pa, pb = headA, headB
while d1 > d2:
pa = pa.next; d1 -= 1
while d2 > d1:
pb = pb.next; d2 -= 1
while pa is not pb and pa is not e1 and pb is not e1:
pa = pa.next; pb = pb.next
return pa if pa is pb else e1 # if none before entry, entry is intersection
else:
# Different entry nodes: cycles may still be connected if entries are in same cycle
# Walk one cycle starting at e1 to see if we can reach e2
p = e1.next
while p is not e1:
if p is e2:
return e1 # cycles intersect; any node in shared cycle is acceptable (return e1 or e2)
p = p.next
return None # disjoint cycles
Key points:- detect_cycle_entry uses Floyd and finds the exact cycle start.- If both acyclic: align lengths and walk — O(n).- If both cyclic: - same entry: intersection can be before or at entry; treat entry as boundary to check earlier intersection. - different entries: check whether entries lie on same cycle by walking one cycle; if so lists intersect somewhere in cycle.Time complexity: O(N+M) where N,M are lengths up to first cycle + cycle lengths. Space: O(1).Edge cases: null heads, identical head pointers, single-node cycles, long cycles; one cyclic & one not (no intersection).