Given the heads of two singly linked-lists headA
and headB
, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null
.
Note that the linked lists must retain their original structure after the function returns.
For example, the following two linked lists begin to intersect at node c1
:
4 -> 1 -> 8 -> 4 -> 5
5 -> 6 -> 1 -> 8 -> 4 -> 5
In the example above, the lists intersect at the node with value 8.
Example 1:
Input: listA = [4,1,8,4,5], listB = [5,6,1,8,4,5]
Output: Node with value 8
Example 2:
Input: listA = [1,9,1,2,4], listB = [3,2,4]
Output: Node with value 2
Example 3:
Input: listA = [2,6,4], listB = [1,5]
Output: null
Could you write a solution that runs in O(m + n) time and uses only O(1) memory?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We want to find where two lists connect, like two roads merging into one. The most straightforward way is to check every possible pair of locations from the two lists to see if they are the same point. This approach is like comparing each item in one list against every item in the other list until we find a match.
Here's how the algorithm would work step-by-step:
def get_intersection_node_brute_force(head_a, head_b):
current_node_list_a = head_a
# Iterate through each node in the first linked list
while current_node_list_a:
current_node_list_b = head_b
# Compare the current node from the first list
# with every node in the second list
while current_node_list_b:
# Check if the current nodes are the same node
if current_node_list_a == current_node_list_b:
# If the nodes are the same, we've found the intersection
return current_node_list_a
current_node_list_b = current_node_list_b.next
# Move to the next node in the first list
current_node_list_a = current_node_list_a.next
# If there is no intersection, return None
return None
The key insight is that if two lists intersect, their tails will be identical. We first figure out how much longer one list is than the other. Then, we advance the pointer of the longer list by the difference in lengths so both pointers are equidistant from the potential intersection point.
Here's how the algorithm would work step-by-step:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def get_intersection_node(head_a, head_b):
list_a_length = 0
list_b_length = 0
current_node_a = head_a
current_node_b = head_b
while current_node_a:
list_a_length += 1
current_node_a = current_node_a.next
while current_node_b:
list_b_length += 1
current_node_b = current_node_b.next
current_node_a = head_a
current_node_b = head_b
# Advance the pointer of the longer list
if list_a_length > list_b_length:
length_difference = list_a_length - list_b_length
for _ in range(length_difference):
current_node_a = current_node_a.next
elif list_b_length > list_a_length:
length_difference = list_b_length - list_a_length
for _ in range(length_difference):
current_node_b = current_node_b.next
# Move both pointers until they meet or reach the end
while current_node_a and current_node_b:
# Comparing the actual node objects, not just values
if current_node_a == current_node_b:
return current_node_a
current_node_a = current_node_a.next
current_node_b = current_node_b.next
return None
Case | How to Handle |
---|---|
Both linked lists are null | Return null immediately as there can be no intersection. |
One linked list is null, the other is not | Return null immediately as there can be no intersection. |
Both lists are single nodes and they are the same node | Return that single node as it's the intersection. |
Both lists are single nodes and they are different nodes | Return null as there is no intersection. |
The lists intersect at the first node of both lists (same list) | The algorithm should correctly identify the head as the intersection point. |
The lists do not intersect at all | The algorithm should correctly identify that there is no intersection and return null. |
One list is significantly longer than the other | The pointer manipulation approach ensures that differing lengths are accounted for by aligning the tails. |
Lists are very long, approaching memory limits | The solution should perform efficiently without creating excessive copies or auxiliary data structures, minimizing memory usage. |