剖析相交链表:LeetCode 160 的巧妙解法
2024-02-19 00:00:50
在编程世界里,LeetCode 犹如一座代码试炼场,其中第 160 题——相交链表,以其独特的解法吸引着无数开发者。这道看似简单的题目,却蕴含着算法设计的精髓。本文将带你深入理解这道题,并解析其背后的巧妙思路,助你提升算法思维能力。
当我们面对两条可能相交的链表时,一个直接的想法是遍历每个链表,并将节点存储在一个集合中。然后,遍历另一个链表,检查每个节点是否在集合中出现过。如果出现,则说明找到了相交节点。这种方法虽然简单易懂,但需要额外的空间来存储节点。有没有更优雅、更节省空间的解决方案呢?
答案是肯定的,那就是 双指针法 。这种方法的核心思想是利用两个指针,分别从两个链表的头节点出发,以相同的速度遍历链表。当其中一个指针到达链表尾部时,将其指向另一个链表的头节点,继续遍历。当另一个指针也到达链表尾部时,将其指向第一个链表的头节点,继续遍历。如果两个链表存在相交节点,那么这两个指针最终会在相交节点相遇。
为什么这种方法能够找到相交节点呢?我们可以想象一下,如果两个链表相交,那么从相交节点到链表尾部的部分是相同的。当两个指针分别遍历完各自的链表后,它们相当于都走过了各自链表的长度,再加上从相交节点到链表尾部的长度。因此,它们最终会在相交节点相遇。
为了更好地理解双指针法,我们来看一个具体的例子。假设有两个链表 A 和 B,它们的结构如下:
A: 1 -> 2 -> 3 -> 4 -> 5
B: 6 -> 7 -> 4 -> 5
相交节点是 4。
我们使用两个指针 ptrA 和 ptrB,分别指向链表 A 和 B 的头节点。
- ptrA 指向 1,ptrB 指向 6。
- ptrA 指向 2,ptrB 指向 7。
- ptrA 指向 3,ptrB 指向 4。
- ptrA 指向 4,ptrB 指向 5。
- ptrA 指向 5,ptrB 指向 null。
- ptrB 指向 1,ptrA 指向 null。
- ptrA 指向 6,ptrB 指向 2。
- ptrA 指向 7,ptrB 指向 3。
- ptrA 指向 4,ptrB 指向 4。
此时,ptrA 和 ptrB 都指向了相交节点 4,算法结束。
下面是用 Python 实现双指针法的代码:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def getIntersectionNode(headA: ListNode, headB: ListNode) -> ListNode:
if headA is None or headB is None:
return None
ptrA = headA
ptrB = headB
while ptrA != ptrB:
ptrA = headB if ptrA is None else ptrA.next
ptrB = headA if ptrB is None else ptrB.next
return ptrA
双指针法不仅思路巧妙,而且代码简洁易懂,时间复杂度为 O(m+n),空间复杂度为 O(1),其中 m 和 n 分别是两个链表的长度。
常见问题解答
1. 双指针法一定能找到相交节点吗?
是的,如果两个链表存在相交节点,那么双指针法一定能找到它。
2. 如果两个链表不相交,双指针法会发生什么?
如果两个链表不相交,那么两个指针最终都会指向 null,算法会返回 null。
3. 双指针法的效率如何?
双指针法的时间复杂度为 O(m+n),空间复杂度为 O(1),是一种非常高效的算法。
4. 双指针法还有哪些应用场景?
除了检测链表是否相交,双指针法还可以用于检测链表中是否存在环,以及寻找链表的中间节点等。
5. 如何学习更多关于双指针法的知识?
可以通过阅读算法书籍、观看算法视频教程,以及练习 LeetCode 上的相关题目来学习更多关于双指针法的知识。
希望本文能够帮助你理解 LeetCode 160 相交链表这道题,并掌握双指针法的应用。在算法学习的道路上,不断探索和实践,才能提升自己的算法思维能力。