链表面试题7之相交链表

来了来了,这道题才是值得我们奇思妙想的题,链接在下面。

160. 相交链表 - 力扣(LeetCode)

看完题目一脸懵吗,没关系,我们还得看示例

还是一脸懵怎么办?? 两个链表相交的方式有几种?

我们再来仔细看一下这道题

这里我们就看到了,可能出现三种形式的相交,那我们就要在想一下,这三种情况下,我们应该怎么去判断这两个链表是相交的。

为什么是找地址而不是比值呢?我们就把图放大来看看:

这里我们看到,困扰我们的,是两个链表不等长,就像示例1中,即使我们的比值一样了,但是所在位置不一样,不一定是相交。所以在这里,还是用我们的地址来判断最为稳妥。

好了,那我们来试试看,能不能用双指针法来解决,但是你会很直观发现不可行,因为链表长度是不相同的。 那怎么解决呢?

那我们就要找两个链表的长度差了,这里不是链表长短不一样阻碍了我吗?那我干脆让他等长好了。让长的链表先走两个链表之间的长度差次。为什么可以这样做?看图。无论我这个链表多长,那我相交节点前的两个链表肯定有一个节点是对齐的。

这里放一下如何计算长度差:

cs 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    //计算两个链表长度
    ListNode* pa = headA , *pb = headB;
    int sizeA = 0,sizeB = 0;
    while(pa){
        ++sizeA;
        pa = pa->next;
    }
    while(pb)
    {
        ++sizeB;
        pb = pb->next;
    }
    //计算长度差 -- 绝对值(可以使用函数abs)
    int gap = abs(sizeA - sizeB);
 
    //找大小链表 -- 让大链表走gap 步
    ListNode* longList = headA;
    ListNode* shortList = headB;
    if(sizeA < sizeB){
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
        longList = longList->next;
    }
    //遍历链表 -- 找相交结点
    //存在相交结点
    while(longList){
        if(longList == shortList){
            return longList;
        }
        longList = longList->next;
        shortList = shortList->next;
    }
    //不存在相交结点
    return NULL;
 
}

这就是我们的第一种方法:计算长度

第二种方法:走过彼此的路

除了计算链表长度外,我们还可以利用 两链表长度和相等 的性质来使得两个遍历指针同步

具体做法是:先遍历其中一个链表,当到底末端后跳到另一链表,最后

若两链表没有公共结点,那么两个链表指针都会走过s1+s2个结点,同时到达两链表末尾

若有公共结点,由于最后会同时走到两链表终点,所以倒退回去,两个指针一定会在第一个公共结点处相遇

可以自己在图里跳一遍!利用的就是长度差,一个快一个慢,但是最后走的路都一样,到达终点前的最后一步也一样!!非常奇妙

当然,若两链表等长,那确实不会跳到另一链表,不过链表等长本身指针就是同步的,同样也能找到公共结点

代码量很小,不过需要细致的观察。

cs 复制代码
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
        struct ListNode *p, *q;

        for (p = headA, q = headB; p != q; ){
            if (p != NULL)
                p = p->next;
            else p = headB;
            if (q != NULL)
                q = q->next;
            else q = headA;
        }

        return p;
}

好了,这道题就讲到这里

如果你觉得对你有帮助,可以点赞关注加收藏,感谢您的阅读,我们下一篇文章再见。

一步步来,总会学会的,首先要懂思路,才能有东西写。

相关推荐
Lee川2 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i4 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有4 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有4 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫5 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫5 小时前
Handler基本概念
面试
Gorway6 小时前
解析残差网络 (ResNet)
算法
Wect6 小时前
浏览器缓存机制
前端·面试·浏览器
拖拉斯旋风6 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect6 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript