精选50题之 160. 相交链表

腾讯精选练习(50 题)之 160. 相交链表

原题目链接

编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在这里插入图片描述
在节点 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 个节点。

示例 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 个节点。\

题目分析

这种题做过几个了类似的了,有几个常见的思路:直接求解(双循环遍历)、hash法(存储再检查)、双指针法。
直接求解时间复杂度O(N^2),而hash法空间复杂度O(N),相比之下双指针法复杂度更优秀。

解题分析

其实双指针有很多具体的实现,不同跳转规也不同,不能直接套用。

Q:如何定义查找成功?
A:需要同时走到一点且为可以指出相交节点(如果存在)
Q:如何同时走到?
A:链表一长度可表示为 a + c、链表二长度可表示为为 b + c(c为公共部分)
Q:在某种组合的情况下…
A:对,a + c + b = b + c + a,且下一节点就是相交节点。

代码实现

失败案例,频频报错,debug心态爆炸。贴上来作为警示:先想好再写?

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
       if(!headA || !headB)
           return nullptr; // 特殊情况
        ListNode *a = headA;
        ListNode *b = headB;
        int flag = 0;
        int res = 1;
        while(a -> next && b -> next)
        {
            a = a -> next;
            b = b -> next;
        }
        if(!a -> next && !b -> next)
        {
            a = headB;
            b = headA;
        }
        else if(a -> next)
        {
            b = headA;
            flag = 1;
            a -> next;
            while(a -> next)
            {
                a = a -> next;
                b = b -> next;
            }
        }
        else
        {
            a = headB;
            flag = 2;
            b -> next;
            while(b -> next)
            {
                b = b -> next;
            }
        }
        if(flag == 1)
        {
            a = headB;
            b = b -> next;
        }
        else
        {
            b = headA;
            a = a -> next;
        }
        if(!a || !b)
        {
            return nullptr;
        }
        while(!a || !b )
        {
            if(a == b)
                return a;
            if(a  == nullptr || b  == nullptr)
            {
                res = 0;
                break;
            }
            a = a -> next;
            b = b -> next;
        }
            return nullptr;
    }
};

把计数统计单独提出来,作为lenA 和 LenB,同时不再移到头结点同时一个个移动,直接移动头结点。核心是减少if…else 判断!!!

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(!headA || !headB)    
            return nullptr;
        ListNode *A = headA;
        ListNode *B = headB;
        int lenA = 0;
        int lenB = 0;
        while(A){
            lenA ++;
            A = A -> next;
        }
        while(B){
            lenB ++;
            B = B -> next;
        }
        int i = max(lenA,lenB) - min(lenA,lenB);
        if(lenA > lenB) 
            for(i; i > 0; -- i)
                headA = headA -> next;
        else
            for(i; i > 0; -- i) 
                headB = headB -> next;
        while(headA)
        {
            if(headA == headB)  
                return headA;
            headA = headA -> next;
            headB = headB -> next;
        }
        return nullptr;
    }
};

在这里插入图片描述
复杂度分析:

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

其他方式

基于三元运算符的极短实现,很巧妙。
Whyzzj 的回答

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        //假设A比B长
    if(headA==NULL||headB==NULL)return NULL;
    struct ListNode* pA=headA;
    struct ListNode* pB=headB;
    while(pA!=pB)//遍历两个链表
    {
        pA=pA==NULL?headB:pA->next;//构造链表D
        pB=pB==NULL?headA:pB->next;//构造链表C
        
    }
    return pA;
    }
};

写在最后

无话可说

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值