题目
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
代码
方法一:双指针
这个方法的关键之处在于,链表A的非公共部分为a,链表B的非公共部分为b,两个链表的公共部分为c,当指针A遍历完a+c+b,指针B遍历完b+c+a时这两个指针一定在公共部分的第一个数相遇,如果没有公共部分就会同时指向null
listA = [1,9,1,2,4],listB = [3,2,4]
指针A遍历过程:1-9-1-2-4-null-3-2
指针B遍历过程:3-2-4-null-1-9-1-2
在2处相遇
这里需要注意的时题目中的例子listA = [4,1,8,4,5], listB = [5,6,1,8,4,5],相交的值是8而不是1,这是因为题目中设定的是8及其以后的数值相交,共用一个地址,而节点1的初始化时只是这个节点的值相同但是地址不相同,所以这里答案是8,而不是1。
在代码中是如何识别出上述例子中相交点是8的呢?是因为无论pA=pA.next或是pB=pB.next,都是地址的传递,比较的是这两个地址是否相同,而不是单纯的两个数值的比较。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
pA,pB=headA,headB # 初始化pA,pB为链表headA,head的头节点
while pA!=pB:
if pA:
pA=pA.next
else:
pA=headB
if pB:
pB=pB.next
else:
pB=headA
return pA
方法二:哈希集合
需要注意的是这段代码中将将hashset= set() 改为hashset= [];将hashset.add(temp)改为hashset.append(temp),这段代码会出现超时的原因是:
关键原因:in 操作的时间复杂度
集合(set)的 in 操作:
集合底层基于哈希表实现,in 操作的时间复杂度是 O(1)。检查元素是否存在时,直接通过哈希值定位,无需遍历整个集合。
列表(list)的 in 操作:
列表底层是顺序存储的数组,in 操作的时间复杂度是 O(n)。检查元素是否存在时,需要从头到尾遍历整个列表。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
hashset=set()
temp=headA
while temp:
hashset.add(temp)
temp=temp.next
temp=headB
while temp:
if temp in hashset:
return temp
temp=temp.next
return None