题目:给两个单链表的头节点heada和headb,请找出并返回两个单链表相交的起始节点。如果两个链表不存在相较节点,返回null。
两个链表在C1开始相交。
intersectval:相交的起始节点的值,如果不存在相交节点,这一值为0
listA:第一个链表
listB:第二个链表
skipA:在listA从头节点开始,跳到交叉节点的节点数
skipB:在listB从头节点开始跳到交叉节点的节点数
方法一:哈希集合
判断链表是否相交,可以使用哈希集合存储链表节点。
首先遍历链表headA,并将链表headA的每个节点加入哈希集合中,然后遍历链表headB,对于遍历到的每个节点,判断该节点是否在哈希集合中:
1.如果当前节点不在哈希集合中,则继续遍历下一个节点
2.如果当前节点在哈希集合中,则后面的节点都在哈希集合中,即从当前节点开始的所有节点都在两个链表的相交部分,因此在链表headB中遍历到的第一个哈希集合的节点就是两个链表相交的节点,返回该节点。
如果链表headB中的所有节点都不在哈希集合中,则两个链表不相交,返回null
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
visited=set() #创建集合
temp=headA #指向headA的头节点
while temp: # 循环遍历 headA 的所有节点
visited.add(temp) #将temp加入集合,表示该节点已经访问过
temp=temp.next #移动到下一个节点,直到结束
temp=headB #重置指针,让其指向B
while temp: #遍历B
if temp in visited: # 如果当前节点在集合中,说明它是交点
return temp
temp=temp.next
return None # 如果没有交点,返回 None
时间复杂度:O(M+N)M和N是链表的长度
空间复杂度:O(M),链表A 的长度,需要使用哈希表存储A的全部节点
方法二:双指针
只有当链表A和链表B都不为空时,两个链表才可能相交,因此首先判断链表headA和headB是否为空,如果其中至少一个链表为空,则两个链表一定不相交,返回null
当链条A和链条B都不为空时,创建两个指针PA和PB,初始时分别指向两个链条的头节点,然后将两个指针依次遍历两个链条的每个节点,具体做法如下:
每步操作需要同时更新指针PA和PB
如果指针PA不为空,则将指针PA移到下一个节点,如果指针PB不为空,则将指针PB移到下一个节点
如果指针pA 为空,则将指针 pA 移到链表 headB 的头节点,同样,如果指针PB为空,则将指针PB移到链条headA的头节点。
当指针PA和PB指向同一个节点或者都为空时,返回它们指向的节点或者null
证明(源自官网)
下面提供双指针方法的正确性证明。考虑两种情况,第一种情况是两个链表相交,第二种情况是两个链表不相交。
情况一:两个链表相交
链表 headA 和 headB 的长度分别是 m 和 n。假设链表 headA 的不相交部分有 a 个节点,链表 headB 的不相交部分有 b 个节点,两个链表相交的部分有 c 个节点,则有 a+c=m,b+c=n。
如果 a=b,则两个指针会同时到达两个链表相交的节点,此时返回相交的节点;
如果 a!=b,则指针 pA 会遍历完链表 headA,指针 pB 会遍历完链表 headB,两个指针不会同时到达链表的尾节点,然后指针 pA 移到链表 headB 的头节点,指针 pB 移到链表 headA 的头节点,然后两个指针继续移动,在指针 pA 移动了 a+c+b 次、指针 pB 移动了 b+c+a 次之后,两个指针会同时到达两个链表相交的节点,该节点也是两个指针第一次同时指向的节点,此时返回相交的节点。
情况二:两个链表不相交
链表 headA 和 headB 的长度分别是 m 和 n。考虑当 m=n 和 m!=n 时,两个指针分别会如何移动:
如果 m=n,则两个指针会同时到达两个链表的尾节点,然后同时变成空值 null,此时返回 null;
如果 m!=n,则由于两个链表没有公共节点,两个指针也不会同时到达两个链表的尾节点,因此两个指针都会遍历完两个链表,在指针 pA 移动了 m+n 次、指针 pB 移动了 n+m 次之后,两个指针会同时变成空值 null,此时返回 null。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if not headA or not headB: #如果 headA或headB 是 None,说明链表为空,不可能有交点
return None
pA,pB=headA,headB ## 初始化两个指针,分别指向 headA 和 headB
while pA !=pB: #当 pA 和 pB 不相等时继续遍历
pA=headB if pA is None else pA.next # pA 走完 A 之后跳转到 B
pB=headA if pB is None else pB.next # pB 走完 B 之后跳转到 A
return pA # 返回交点
时间复杂度:O(M+N)遍历各链表一遍
空间复杂度:O(1)