[剑指Offer]:两个链表的第一个公共节点

152 阅读5分钟

文章目录


题目描述

两个链表,判断是否相交,找出相交的第一个点?

如下面的两个链表:

在这里插入图片描述

在节点 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 个节点。

注意:

  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。

题解思路 – 双指针法

可能这辈子你我无法在一起,但有限次轮回后我们终将在一起

  • 你变成我,走过我走过的路。
  • 我变成你,走过你走过的路。
  • 然后我们便相遇了…

复杂度分析:

  • 时间复杂度:O(n + m)
  • 空间复杂度:O(1)

代码解答:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == nullptr || headB == nullptr) return nullptr;
        ListNode* p = headA;
        ListNode* q = headB;
        while(p != q)
        {
            if(p == nullptr)  p = headB;	// p指向另一个链表头
            else p = p->next;
            if(q == nullptr) q = headA;		// q指向另一个链表头
            else q = q->next;
           
        }
        return p;
    }
};

扩展

首先应该清楚两个单链表相交要么都是无环链表,要么都是有环链表,不存在一个有环链表和一个无环链表相交,因为两个链表一旦相交则后续的链表都应该是相同的

  1. 将其中任意一个链表的环打破,即让尾结点指向null(记下保存原本应当指向的位置),然后判断第二个链表是否含有环,若第二个链表无环则相交,否则不相交
  2. 利用 判断单链表是否有环 的方法,对链表使用两个快慢指针进行判断是否有环,两个指针的碰撞点即在环上,那么判断链表二的环上是否包含该碰撞点就可以判断两个链表是否相交了

两个无环链表相交

如果两个单链表有共同的节点,那么从第一个节点开始,后面的节点都会重叠,直至链表结束,因为两个链表中有一个共同节点,则从这个节点里的指针域指向下一个节点的地址就相同,所以相交以后的节点就会相同,直至链表结束,总的模型就像一个“Y”

在这里插入图片描述

解法:

(1)暴力解法

  从头开始遍历一个链表,遍历第一个链表中的每个节点时,同时从头到尾遍历第二个链表,看是否有相同的节点,第一次找到相同的节点即第一个交点;若遍历结束未找到相同的节点,即不存在交点,时间复杂度为O(n^2)

(2)遍历链表记录长度

  同时遍历两个链表到尾部,同时记录两个链表的长度。若两个链表最后的一个节点相同,则两个链表相交。有两个链表的长度后,我们就可以知道哪个链表长,设较长的链表长度为len1,短的链表长度为len2。

  节点相同时,则这个节点就是第一个相交的节点。(第二种方法其实是缩短了链表比较的长度)时间复杂度为O(len1+len2)

(3)使用栈

  我们可以从头遍历两个链表。创建两个栈,第一个栈存储第一个链表的节点,第二个栈存储第二个链表的节点,直至链表的所有节点入栈,通过取两个栈的栈顶元素节点判断是否相等即可判断两个链表是否相交。从第一个相交节点之后,后续节点均相交直至链表结束。出栈直至两个节点不相同时,则这个节点的后一个节点是第一个相交节点

(4)哈希表法

  既然两个链表一旦相交,相交节点一定有相同的内存地址,而不同的节点内存地址一定是不同的,那么不妨利用内存地址建立哈希表,如此通过判断两个链表中是否存在内存地址相同的节点判断两个链表是否相交。具体做法是:遍历第一个链表,并利用地址建立哈希表,遍历第二个链表,看看地址哈希值是否和第一个表中的节点地址值有相同即可判断两个链表是否相交。时间复杂度O(length1 + length2)

两个链表都为有环情况

(1)第一个交点在环开始之前

在这里插入图片描述

(2)第一个交点在环入口处

在这里插入图片描述

(3)第一个交点在环内

在这里插入图片描述

判断相交方法:

  针对(1)和(2)两种情况我们可以采用和上述无环链表的判断方法一样,针对第三种有环链表,我们可以分别找到链表一和链表二的环入口节点,各自的环入口节点即为各自第一次相交的节点


如有帮助到您,可以多多点赞、评论鼓励哟~~~