【LeetCode热题100道笔记】相交链表

题目描述

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:
在这里插入图片描述

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

思考一(遍历+哈希表)

先遍历一遍任意一个链表,把每个节点存到哈希表中。再遍历另一个链表的每个节点,判断节点是否在哈希表中存在,如果存在就返回这个节点,这个节点必然是第一个交点。

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    const set = new Set();
    let node = headA;
    while (node) {
        set.add(node);
        node = node.next;
    }

    node = headB;
    while (node) {
        if (set.has(node)) {
            return node;
        }
        node = node.next;
    }
    
};

思考二(双指针法)

双指针法的核心思路是消除两个链表的长度差异,使它们能够同步到达相交点(如果存在):

  1. 长度差异是关键障碍:两个链表若相交,从相交点到尾端的部分是共用的,差异只存在于相交点之前的部分。
  2. 先计算长度差:分别遍历两个链表得到长度 lenA 和 lenB,求出差值 count。
  3. 让长链表先行:让指向长链表的指针先移动 count 步,此时两个指针到各自链表尾端的距离相等。
  4. 同步遍历找交点:两个指针同时向后移动,若相遇则该节点为相交起点;若遍历结束仍未相遇,则无交点。

这种方法只需两次完整遍历(计算长度)加一次同步遍历,时间复杂度为 O(m+n),空间复杂度为 O(1),是高效且节省空间的解决方案。

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    let nodeA = headA;
    let nodeB = headB;

    let lenA = 0, lenB = 0;
    while (nodeA) {
        lenA++;
        nodeA = nodeA.next;
    }
    while (nodeB) {
        lenB++;
        nodeB = nodeB.next;
    }

    let count = Math.abs(lenA - lenB);
    if (lenA > lenB) {
        nodeA = headA;
        nodeB = headB;
    } else {
        nodeA = headB;
        nodeB = headA;
    }

    while (nodeA && count > 0) {
        count--;
        nodeA = nodeA.next;
    }    

    while (nodeA && nodeB) {
        if (nodeA === nodeB) return nodeA;
        nodeA = nodeA.next;
        nodeB = nodeB.next;
    }

    return null;    
};

思考三(更简洁的双指针法)

该双指针解法是对“消除长度差”思路的极致简化,核心在于让两个指针“自动抵消”链表长度差异,无需单独计算长度,逻辑更精妙:

  1. 打破“固定遍历顺序”:不预先计算链表长度,而是让指针 pA 从 headA 出发、pB 从 headB 出发,同步向后遍历。
  2. “跨界”遍历补全长度差:当某一指针遍历完自身链表(指向 null)时,立即转向另一链表的头部继续遍历。例如:
    • 若 lenA < lenB,pA 会先走完 headA,转而遍历 headB;此时 pB 仍在 headB 上,直到 pB 也走完 headB 并转向 headA。
    • 最终,两个指针会“自动对齐”到距离各自链表尾端相等的位置(相当于抵消了长度差)。
  3. 相遇即交点,遍历完即无交点
    • 若两链表相交,pA 和 pB 会在遍历过程中相遇,此时相遇节点就是相交起始节点(因后续路径完全共用)。
    • 若两链表无交点,两个指针最终都会遍历完 headA + headB 的所有节点,同时指向 null,循环终止并返回 null。

该方法仅需一次遍历(实际是两指针各遍历“自身链表+另一链表”的部分节点),时间复杂度仍为 O(m+n),但代码更简洁;空间复杂度保持 O(1),且避免了单独计算长度的步骤,执行效率更优。

代码

var getIntersectionNode = function(headA, headB) {
    if (headA === null || headB === null) {
        return null;
    }
    let pA = headA, pB = headB;
    while (pA !== pB) {
        pA = pA === null ? headB : pA.next;
        pB = pB === null ? headA : pB.next;
    }
    return pA;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值