如影随形,寻觅双链交点:LeetCode 160 相交链表算法之美
2024-02-01 11:19:12
在算法竞赛和编程实践中,链表数据结构的使用可谓随处可见,解决各种复杂问题时,它总是能展现出独到的优势。LeetCode 160 相交链表便是这样一个极具代表性的问题,它要求我们寻找到两个单链表的相交起始节点,为算法工程师们提供了绝佳的挑战。
算法问题
给出两个单链表的头节点 headA 和 headB ,找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
理解题意:
题目要求我们找到两个单链表的相交起始节点,关键在于理解相交起始节点的概念。两个单链表的相交起始节点是指两个链表中第一个相同的节点,它是两个链表共同拥有的最长公共后缀。如果两个链表没有交点,则不存在相交起始节点,需要返回 null。
算法思路:
解决此问题,我们可以采用双指针法。
第一步,设置两个指针,分别指向链表 headA 和 headB 的头节点。
第二步,让两个指针同时向前移动,每移动一步,就将指针指向下一个节点。
第三步,当其中一个指针到达链表末尾时,将其重置为另一个链表的头节点。
第四步,重复步骤二和步骤三,直到两个指针相遇或都到达链表末尾。
第五步,如果两个指针相遇,则相遇点就是相交起始节点;如果两个指针都到达链表末尾,则两个链表没有交点,返回 null。
算法流程:
- 初始化两个指针,分别指向链表 headA 和 headB 的头节点。
- while (headA != null && headB != null) {
- if (headA == headB) {
- return headA; // 两个指针相遇,说明找到交点。
}
- return headA; // 两个指针相遇,说明找到交点。
- headA = headA.next;
- headB = headB.next;
}
- if (headA == null) {
- headA = headB; // headA 指针指向链表 headB 的头节点。
} else { - headB = headA; // headB 指针指向链表 headA 的头节点。
}
- while (headA != null) {
- if (headA == headB) {
- return headA; // 两个指针相遇,说明找到交点。
}
- return headA; // 两个指针相遇,说明找到交点。
- headA = headA.next;
- headB = headB.next;
}
- return null; // 两个指针都到达链表末尾,说明没有交点。
复杂度分析:
时间复杂度:O(m + n),其中 m 和 n 分别是链表 headA 和 headB 的长度。
空间复杂度:O(1),因为我们只需要两个指针,不需要额外的空间。
实现代码:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 初始化两个指针,分别指向链表 headA 和 headB 的头节点。
ListNode pA = headA;
ListNode pB = headB;
// 让两个指针同时向前移动,每移动一步,就将指针指向下一个节点。
while (pA != null && pB != null) {
// 如果两个指针相遇,则相遇点就是相交起始节点。
if (pA == pB) {
return pA;
}
// 如果其中一个指针到达链表末尾,则将其重置为另一个链表的头节点。
if (pA.next == null) {
pA = headB;
} else {
pA = pA.next;
}
if (pB.next == null) {
pB = headA;
} else {
pB = pB.next;
}
}
// 如果两个指针都到达链表末尾,则两个链表没有交点,返回 null。
return null;
}
}
算法要点:
- 双指针法是解决此问题最为简洁有效的方法之一。
- 指针移动过程中,当其中一个指针到达链表末尾时,将其重置为另一个链表的头节点,巧妙地实现了两个链表的交替遍历。
- 算法的核心思想在于,如果两个链表相交,那么它们的相交起始节点必然是两个指针相遇的节点。
除了双指针法,还有其他解决方法,例如哈希表法和栈法。
哈希表法:将其中一个链表的所有节点放入哈希表,然后遍历另一个链表,对于每个节点,检查其是否存在于哈希表中,如果存在,则说明找到了相交起始节点。
栈法:将两个链表的节点依次入栈,然后逐个出栈比较,如果两个节点相等,则说明找到了相交起始节点。
不同的方法各有其优劣,双指针法在时间和空间复杂度上都具有较好的表现,哈希表法在链表长度较长时性能较好,栈法在链表长度较短时性能较好。