LeetCode --- 链表系列 --- 相交链表

相交链表

题目

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


如下面的两个链表:

在节点 c1 开始相交。


注意:

如果两个链表没有交点,返回 null.

在返回结果后,两个链表仍须保持原有的结构。

可假定整个链表结构中没有循环。

程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。


示例

示例 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。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


解题思路

力扣题解

// 标记法
1、分别定义 `a、b` ,并进行赋值

2、循环对其中一条链表每个元素做一个 `标记`

3、循环第二条链表,如果相交,那么可以在某个位置找到 `标记`

力扣较好题解

// 双指针法
1、分别定义 `a、b` ,并进行赋值

2、
若 `a、b` 存在相交节点,则 `a、b` 在相交节点后的是 `同一条链表`
那么应该将 `a、b` 向右对齐,而后 `从左往右` 开始对比 a 和 b
但是 a 和 b 不一定长度一样,所以,我们可以将 `a、b` 组合成 `ab` 和 `ba`
以 `a` 开头 链接 `b` 得到 `a -> b`,即链表 `ab`
以 `b` 开头 链接 `a` 得到 `b -> a`, 即链表 `ba`
`ab` 和 `ba` 长度相等, `从左往右` 对比,若相等,那么该元素就是 `相交节点`
同时间分别遍历 `ab、ba` ,将在某个节点找到相同的元素
a: 1 - 3 - 5 - 7 - 9
b:     2 - 6 - 7 - 9
a - b : 1 - 3 - 5 - 7 - 9 - 2 - 6 - 7 - 9
        |       a       |   |     b     |
b - a : 2 - 6 - 7 - 9 - 1 - 3 - 5 - 7 - 9
        |     b     |   |       a       |

3、循环对比
若 `a === b`
若都为 `null` 说明 `ab` 和 `ba` 都遍历到结尾了,都是 `null` ,返回 `null`
若不为 `null` ,且相等,说明找到 `相交的节点` ,返回该节点

若 `a !=== b`
a, b 取各自的下一个值
若下一个值不存在,则赋值为 另外一个链表的开头(即上面所说的链表相加)

题解

力扣题解

// 用时一般,内存消耗较多
执行用时: 96 ms
内存消耗: 44.2 MB

// 标记法
let getIntersectionNode = function(headA, headB) {
    // 分别定义 a,b,并进行赋值
    let [a, b] = [headA, headB];

    
    // 循环对其中一条链表每个元素做一个标记
    while(a) {
        a.flag = 1
        a = a.next
    }
    // 循环第二条链表,如果相交,那么可以在某个位置找到标记
    while(b) {
        if (b.flag) return b
        b = b.next
    }
    return null
}

力扣较好题解

// 用时较好,内存消耗较好
执行用时: 88 ms
内存消耗: 42.3 MB

// 双指针法
let getIntersectionNode = function(headA, headB) {
    // 分别定义 a,b,并进行赋值
    let [a, b] = [headA, headB];

    // 双指针法:
    // 两条链表 a,b:
    // 若 a、b 存在相交节点,则 a、b 在相交节点后的是同一条链表
    // 那么应该将 a b 向右对齐,而后从左往右开始对比 a 和 b
    // 但是 a 和 b 不一定长度一样,所以,我们可以将 a、b 组合成 ab 和 ba
    // 以 a 开头 链接 b 得到 a -> b,即链表 ab
    // 以 b 开头 链接 a 得到 b -> a, 即链表 ba
    // ab 和 ba 长度相等,从左往右对比,若相等,那么该元素就是相交节点
    // 同时间分别遍历 ab、ba,将在某个节点找到相同的元素
    // a: 1 - 3 - 5 - 7 - 9
    // b: 2 - 6 - 7 - 9
    // a - b : 1 - 3 - 5 - 7 - 9 - 2 - 6 - 7 - 9
    //         |       a       |   |     b     |
    // b - a : 2 - 6 - 7 - 9 - 1 - 3 - 5 - 7 - 9
    //         |     b     |   |       a       |
    // 持续循环
    while(true) {
        // 直到 a === b 
        // 若都为 null 说明 a 和 b 都遍历到结尾了,都是 null,返回 null
        // 若不为 null ,且相等,说明找到相交的节点,返回该节点
        // 注意此处要加分号隔离下面的语句
        if (a === b) return a;

        // 若不相等
        // a, b 取各自的下一个值
        // 若下一个值不存在,则赋值为 另外一个链表的开头
        [a, b] = [a ? a.next : headB, b ? b.next : headA];
    }
}

原文地址:https://www.cnblogs.com/linjunfu/p/12836406.html