songyy5517 / DataStructures-Algorithms

0 stars 0 forks source link

剑指 Offer 52: 两个链表的第一个公共节点 #53

Open songyy5517 opened 1 year ago

songyy5517 commented 1 year ago

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表: This is an image

在节点 c1 开始相交。

示例 1: This is an image

输入: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 个节点。

分析 当两个链表的长度不确定时,我们想要同时遍历到两个链表的尾部,这时就可以使用双指针同时遍历两个链表。当一个指针到达链表末尾时,重新指向另一个链表的头节点。这样就能保证最终两个指针同时到达两个链表的尾部。

songyy5517 commented 1 year ago

思路:双指针遍历相遇

  1. 异常处理;
  2. 定义双指针;
  3. 当两指针未相遇时循环遍历链表;
    • 两指针相遇(相等)时的节点若不为空,则为公共节点;
    • 若两指针都为空,则说明两链表没有公共节点。
    • 若一个指针到达链表的末尾,则将其重置为另一个链表的头节点。(目的:保证下一次遍历时各自链表中剩下的节点数相等)
  4. 返回相遇时指针指向的节点。

复杂度分析

songyy5517 commented 1 year ago
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
class Solution {
    ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 思路:双指针相遇
        // 1. 异常处理
        if (headA == null || headB == null)
            return null;

        // 2. 双指针遍历链表
        ListNode pa = headA;
        ListNode pb = headB;

        // 3. 若指针到达链表尾部,则重置为另一个链表的头节点。
        while (pa != pb){    // !若无公共节点,则会同时指向null,而不是陷入死循环
            pa = pa == null ? headB : pa.next;  // !  ?:的写法
            pb = pb == null ? headA : pb.next;
        }

        return pa;
    }
}

// 为什么示例1的结果不是1? 
songyy5517 commented 1 year ago

不熟悉的地方

2023/5/18

2024/1/18

2024/1/22 2024/3/14