剑指offer 52 - 两个链表的第一个公共结点 - python

89 阅读3分钟

题目描述:

编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:


在这里插入图片描述

在节点 c1 开始相交。

示例 1:


在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:


在这里插入图片描述

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:


在这里插入图片描述

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
 

注意:

  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构
  • 可假定整个链表结构中没有循环
  • 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

思路:

具有公共节点的链表如下所示:

在这里插入图片描述
链表从后往前第一个不同的节点前的那个就是第一个公共节点,但链表从后往前无法遍历,因此可以将链表放入栈中,然后依次出栈并记录当前相同的节点。

  • 如果下个节点不同,则输出当前节点为第一个公共节点
  • 否则,继续出栈直到碰到第一个彼此不同的节点,输出第一个公共节点
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        def helper(head):
            l = []
            while head:
                l.append(head)
                head = head.next
            
            return l

        if headA is None or headB is None:
            return None
        
        temp = None
        l1, l2 = helper(headA), helper(headB)
        while l1 and l2:
            s1, s2 = l1.pop(), l2.pop()
            if s1 != s2:
                return temp
            else:
                temp = s1
        
        return temp 

但是上面的解法使用了两个栈来存储两个链表中的元素,此时的空间复杂度为 O ( N ) O(N) O(N),时间复杂度为 O ( N ) O(N) O(N)。

如果想要让空间复杂度控制在 O ( 1 ) O(1) O(1),那么就不能使用额外的空间,只能在链表本身上操作。

  • 获取两个链表的长度,同时设置两个指针 p p p和 q q q,并让 p p p指向更长的那个链表, q q q指向较短的那个链表
  • 计算长度差 n u m num num,让 p p p多往前走 n u m num num步,然后依次往后找直到找到第一个值相同的结点即第一个公共结点
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        def helper(head):
            l = 0
            while head:
                l += 1
                head = head.next
            
            return l

        if headA is None or headB is None:
            return None
    
        l1, l2 = helper(headA), helper(headB)
        
        if l1 > l2:
            p, q = headA, headB
        else:
            q, p = headA, headB
        
        l = abs(l1 - l2) 
        while l and p:
            p = p.next
            l -= 1
    
        while p and q:
            if p == q:
                return p
            else:
                p, q = p.next, q.next 
        
        return None