
Problem Statement
In this task, we are given the starting nodes (heads) of two singly linked lists, denoted as headA
and headB
. The goal is to determine if these two lists intersect at some point and, if they do, return the node at which they begin to intersect. If there is no intersection point, the function should return null
.
Linked lists are linear data structures where each element, known as a node, contains a value and a reference to the next node in the sequence. The problem asserts that there are no cycles in either of the linked lists, meaning they don't loop back on themselves.
To clarify, intersection here implies that nodes from both lists start sharing the same node instances from a certain point onwards. Importantly, even if two nodes from each list have the same value, they may not necessarily be the intersection point unless they are literally the same node (i.e., they occupy the same space in memory).
The task's complexities are compounded by the expectation that the original structure of the linked lists must be preserved throughout the execution of the function. This means you cannot modify the lists to solve the problem, such as by changing pointers.
The challenge is made more approachable by additional information supplied by a "Custom Judge" for testing:
intersectVal
specifies the value expected at the intersection node, or0
if there is no intersection.listA
andlistB
are the sequences of the linked lists.skipA
andskipB
describe the number of nodes to skip from the start of each list to reach the intersection point, enabling the simulation of various list configurations to validate solutions robustly.
Examples
Example 1
Input:
intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
Output:
Intersected at '8'
Explanation:
The intersected node's value is 8 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,6,1,8,4,5]. There are 2 nodes before the intersected node in A; There are 3 nodes before the intersected node in B. - Note that the intersected node's value is not 1 because the nodes with value 1 in A and B (2nd node in A and 3rd node in B) are different node references. In other words, they point to two different locations in memory, while the nodes with value 8 in A and B (3rd node in A and 4th node in B) point to the same location in memory.
Example 2
Input:
intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
Output:
Intersected at '2'
Explanation:
The intersected node's value is 2 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [1,9,1,2,4]. From the head of B, it reads as [3,2,4]. There are 3 nodes before the intersected node in A; There are 1 node before the intersected node in B.
Example 3
Input:
intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
Output:
No intersection
Explanation:
From the head of A, it reads as [2,6,4]. From the head of B, it reads as [1,5]. Since the two lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values. Explanation: The two lists do not intersect, so return null.
Constraints
- The number of nodes of
listA
is in them
. - The number of nodes of
listB
is in then
. 1 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
intersectVal
is0
iflistA
andlistB
do not intersect.intersectVal == listA[skipA] == listB[skipB]
iflistA
andlistB
intersect.
Approach and Intuition
The intersection of two linked lists can be visualized and approached as follows:
Length Calculation:
- First, traverse each list to determine their lengths. This will help in aligning them in the following steps.
Alignment for Intersection:
- Calculate the length difference between the two lists. Start a pointer from the head of the longer list and move it forward by the difference in lengths.
- This ensures that when you subsequently move through both lists step by step, the pointers will reach the end of the lists simultaneously if there's no intersection, or intersect at the same node if there is one.
Simultaneous Traversal:
- With pointers adjusted for any length discrepancy, traverse both lists at the same pace. If they intersect, the pointers will become equal at the intersection node (not just having the same value, but actually being the same node).
- If they completely traverse the lists without this happening, then return
null
indicating no intersection.
This solution strategy ensures that the problem is solved in an optimal time complexity of O(M+N) where M and N are the lengths of the two lists, respectively, with a constant space complexity since only a few pointers are used. This meets the challenge's demands effectively while respecting the constraints provided.
In summary, understanding pointer manipulation and leveraging the characteristics of linked lists regarding traversal and node comparison are crucial in efficiently determining the point of intersection, if any.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
ListNode* findIntersection(ListNode* startA, ListNode* startB) {
ListNode* currentA = startA;
ListNode* currentB = startB;
while (currentA != currentB) {
currentA = currentA == nullptr ? startB : currentA->next;
currentB = currentB == nullptr ? startA : currentB->next;
}
return currentA;
}
};
This solution resolves the problem of finding the intersection node of two singly linked lists. The code, written in C++, defines a method findIntersection
within the class Solution
, which returns the intersected node if an intersection exists, or nullptr
otherwise.
- The function uses two pointers,
currentA
andcurrentB
, initialized at the heads of the two lists,startA
andstartB
. - Both pointers traverse through their respective lists, and once they reach the end, they continue from the start of the other list.
- This step ensures that both pointers cover the same distance, taking into account the difference in lengths of the two lists.
- If the lists intersect, the pointers will meet at the intersection node after a specific number of steps; otherwise, they will both reach the end (
nullptr
), indicating no intersection.
This approach leverages the cyclical traversal by the two pointers to equate their paths, allowing them to find the intersection in linear time and constant space.
public class Solution {
public ListNode findIntersection(ListNode firstHead, ListNode secondHead) {
ListNode firstPointer = firstHead;
ListNode secondPointer = secondHead;
while (firstPointer != secondPointer) {
firstPointer = firstPointer == null ? secondHead : firstPointer.next;
secondPointer = secondPointer == null ? firstHead : secondPointer.next;
}
return firstPointer;
}
}
The provided Java solution identifies the intersection point of two singly linked lists. The technique employed ensures that no additional memory is used, maintaining time complexity at O(m+n), where m and n are the lengths of the two linked lists.
In the solution:
- Define a method
findIntersection
that takes the heads of two linked lists (firstHead
andsecondHead
) as parameters. - Initialize two pointers,
firstPointer
andsecondPointer
, to start at the heads of the two lists respectively. - Utilize a while loop to traverse the lists. The loop continues until the two pointers meet, indicating the intersection point, or if there's no intersection, until both pointers reach the end of the lists (both are null).
- Inside the loop, move each pointer to the next node in its respective list. If a pointer reaches the end of its list, redirect it to the head of the other list.
- The looping mechanism inherently handles the difference in lengths between the two lists by shifting pointers to the start of the opposite list. This guarantee, after traversing at most
2*(m+n)
steps, either an intersection is found, or both pointers simultaneously reach the end of their paths.
At the conclusion of the loop, firstPointer
will either point to the intersection node, or be null
if the lists do not intersect. This efficient method effectively addresses the problem without modifying the original lists or incurring additional space complexity.
struct ListNode *findIntersection(struct ListNode *list1, struct ListNode *list2) {
struct ListNode *pointer1 = list1;
struct ListNode *pointer2 = list2;
while (pointer1 != pointer2) {
pointer1 = pointer1 == NULL ? list2 : pointer1->next;
pointer2 = pointer2 == NULL ? list1 : pointer2->next;
}
return pointer1;
}
The provided C solution effectively identifies the intersection node of two singly linked lists. The core approach utilizes two pointers, pointer1
and pointer2
, each initially set to the heads of list1
and list2
respectively.
Each pointer progresses through its respective list.
Once a pointer reaches the end of its list, it switches to the beginning of the other list.
This crisscrossing continues until both pointers meet at the intersection node or both reach the end (NULL), indicating no intersection.
The main strength of this approach lies in its guarantee to find the intersection in linear time, O(n + m), where n and m are the lengths of the lists. This eliminates the need for additional data structures, making the implementation both time-efficient and space-efficient without additional memory overhead.
This algorithmic solution leverages the concept of two-pointer technique to solve the problem effectively with a simple but clever approach. The conditional operator is used to loop back the pointers to the start of the opposite list once the end of one list is reached, ensuring that any difference in the lengths of the lists is accounted for inherently. This method ensures that if an intersection exists, the pointers will align at the intersection node simultaneously.
var findIntersection = function (list1, list2) {
var current1 = list1;
var current2 = list2;
while (current1 !== current2) {
current1 = current1 === null ? list2 : current1.next;
current2 = current2 === null ? list1 : current2.next;
}
return current1;
};
In the provided JavaScript solution, the problem of finding the intersection point of two singly linked lists is tackled effectively. Here’s a streamlined explanation of how the given function, findIntersection
, works:
- Initialize two pointers,
current1
andcurrent2
, that traverse throughlist1
andlist2
respectively. - Use a while loop that continues until these two pointers meet, which will happen at the intersection node or when both are null (i.e., no intersection).
- Inside the loop, advance each pointer to the next node in its respective list. If a pointer reaches the end of its list (null), it starts over at the beginning of the other list.
- When
current1
andcurrent2
finally meet, the loop breaks and the method returnscurrent1
(orcurrent2
, since both are the same at this point) as the intersecting node. If no intersection exists, it returns null.
This solution leverages the property that by switching the list heads, both pointers will have traversed the same number of nodes (the length of both lists combined) when they meet, thus assuring they meet at the intersection point or conclude with no intersection.
This approach is both space-efficient, requiring no additional data structures, and time-efficient, with a linear time complexity relative to the sum of the lengths of the two lists. Adjustments to the runtime environment or the data structure may require minor adaptations of the function for optimal performance.
class Solution:
def findIntersection(self, list1: ListNode, list2: ListNode) -> ListNode:
pointer1 = list1
pointer2 = list2
while pointer1 != pointer2:
pointer1 = list2 if pointer1 is None else pointer1.next
pointer2 = list1 if pointer2 is None else pointer2.next
return pointer1
The provided Python code defines a function to find the intersection point of two singly linked lists. The function, findIntersection
, utilizes two pointers, pointer1
and pointer2
, each starting at the head of the respective linked lists, list1
and list2
.
- At each step, both pointers move one node forward.
- If a pointer reaches the end of its list, it then moves to the beginning of the other list.
- This continues until the pointers meet, which will be the intersection node or
None
if there is no intersection.
This approach ensures that both pointers traverse exactly len(list1) + len(list2)
nodes. By switching lists, any difference in the length of the lists is counterbalanced, and if the lists intersect, the pointers will eventually meet at the intersection node. The solution returns the node at which both pointers coincide, thus indicating the intersection point. If no intersection exists, the function returns None
.
No comments yet.