算法通关村第一关-白银-链表金典问题之查找公共子节点

一、链表公共子节点的概念

算法通关村第一关-白银-链表金典问题之查找公共子节点_第1张图片

 如上图所示,单链表A和单链表B存在相交点C1,C1结点即为单链表A和单链表B的公共子节点

思考:
1. 两个链表会不会存在多个公共子节点?
A:会,C1,C2,C3都是公共子节点;C1可以被认为是交叉节点,交叉节点只有一个


2. 两个双链表会有公共子节点吗?
A:不会,双链表的定义决定的,双链表节点的pre指向是明确的(只有一个)

二、经典问题:查找两个链表的第一个公共节点

1. 思路分析

方法1:暴力解法

直接按照题意来,两层循环,类似冒泡排序法,将链表A中的每一个结点依次与链表B中的节点进行比较,如果相等即为公共节点。时间复杂度高

方法2:Hash/集合

将链表A中元素全部存到Map/集合里,然后遍历链表B中元素,是否在Map/集合中

方法3:栈(先进后出)

链表A和链表B,后半部分公共节点是一致的。先将两个链表分别压栈,然后同时出栈,比较出栈元素,最后一组出栈相同的元素即为第一个公共节点

方法4:技巧型方法——拼接两个字符串

A+B 与 B+A

若链表A和链表B存在公共节点,则 right_a == right_b,且拼接后 A+B 与B+A 的长度是相同的

算法通关村第一关-白银-链表金典问题之查找公共子节点_第2张图片

 方法5:技巧型方法——差和双指针

链表A和链表B长度可能不一致,获取两个链表的长度差 | lengthA - lengthB |,可以考虑先让较长的链表先走 | lengthA - lengthB | 步,然后借用双指针,比较链表A和链表B的结点,找出公共结点

2. 代码实现(python)

链表定义:

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

方法2实现

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        s = set()
        node1, node2 = headA, headB
        while node1:
            s.add(node1)
            node1 = node1.next

        while node2:
            if node2 in s:
                break
            node2 = node2.next
        return node2

方法3实现

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        s1, s2 = [], []
        node1, node2 = headA, headB
        while node1:
            s1.append(node1)
            node1 = node1.next
        while node2:
            s2.append(node2)
            node2 = node2.next

        c_node = None
        i, j = len(s1)-1, len(s2)-1
        while i>=0 and j>=0 and s1[i]==s2[j]:
            c_node = s1[i]
            i -= 1
            j -= 1
        return c_node

# 容易忽略的一种情况 headA=[1] headB=[1]

方法4实现


class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        node1, node2 = headA, headB
        while node1 != node2:
            node1 = node1.next if node1 else headB
            node2 = node2.next if node2 else headA
        return node1

注:如果没有公共子结点,就会返回None,链表的最后一个节点为None

方法5实现

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        len_a, len_b = 0, 0
        node1, node2 = headA, headB
        while node1:
            len_a += 1
            node1 = node1.next
        while node2:
            len_b += 1
            node2 = node2.next
        
        node1, node2 = headA, headB
        for i in range(len_a - len_b):
            node1 = node1.next
        for i in range(len_b - len_a):
            node2 = node2.next
        
        while node1 and node2 and node1 != node2:
            node1 = node1.next
            node2 = node2.next
        return node1

你可能感兴趣的:(算法,链表,数据结构)