本来想魔怔快慢指针的,发现好像不太行
于是先魔怔哈希表
代码如下:

def FindFirstCommonNode(self , pHead1 , pHead2 ):
    hashtable = dict()
    i = 0
    while pHead1:                  # 将 pHead1 中的结点存入哈希表
        hashtable[pHead1] = i
        pHead1 = pHead1.next
        i += 1

    while pHead2:                  # 在 pHead2 中寻找第一个相同的结点
        if pHead2 in hashtable:
            return pHead2
        pHead2 = pHead2.next
    
    return None

然后想了想,好像可以上双指针
具体思想是先获取两列表的长度,得到长度之差 k
令长的列表头指针先行移动 k 步,再同时移动
代码如下:

def FindFirstCommonNode(self , pHead1 , pHead2 ):
    i1 = self.GetLength(pHead1)     # 获取长度
    i2 = self.GetLength(pHead2)

    k = 0
    p1, p2 = pHead1, pHead2         # 获得差值 k
    if i1 < i2:                     # 同时使最长的链表为 p1
        k = i2 - i1
        p1, p2 = pHead2, pHead1
    else:
        k = i1 - i2
    
    for _ in range(k):              # 使 p1 先走 k 步
        p1 = p1.next
    
    while p1 != p2 and p1 and p2:   # 同时移动 p1 和 p2
        p1 = p1.next                # 寻找相同的结点
        p2 = p2.next                # 没有则 p1 == p2 == None

    return p1


def GetLength(self, head):          # 获得链表长度
    i = 0
    while head:
        head = head.next
        i += 1
    
    return i

但我觉得这样还不够,于是查看评论区
发现自己的思路正确,但做法还不够简洁,于是便有如下想法:

令 p1, p2 同时移动,先抵达表尾的指针代表该链表最短,此时 p1, p2之间的距离刚好为差值 k
若 p1 先抵达表尾,则 pHead1 为短链表,p2 为长链表。令 p1 指向 pHead2 ,再与 p2 同时移动。当 p2 抵达表尾时,此时 p1 已经移动 k 步,令 p2 指向 pHead1 ,当 p1 = p2 时找到公共结点。(若 p2 先抵达队尾同理) 若 p1, p2 同长,则相等时找到公共结点,为 None 时为没有公共结点

代码如下:

def FindFirstCommonNode(self , pHead1 , pHead2 ):
    p1, p2 = pHead1, pHead2
    while p1 != p2:
        p1 = p1.next if p1 else pHead2
        p2 = p2.next if p2 else pHead1

    return p1

妙啊