相交链表习题

题目

相交链表

题目要求

在这里插入图片描述

示例

链接:题目链接

解答

方法一、

自己写的暴力求解法

实现思路

先算出listA的长度,然后算出listB的长度,判断两个链表哪一个比较长,然后让长的链表先走abs(lenA-lenB),然后再将两个指针一起向后访问链表,并且判断两个指针指向的结点是否相等,如果两个指针指向的结点相同时,此结点就为两个链表的相交结点。

时间复杂度和空间复杂度

时间复杂度:O(N)
空间复杂度:O(1)

代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL)
    {
        return NULL;
    }
   
    int lenA = 0;
    int lenB = 0;
    struct ListNode * currA = headA;
    struct ListNode * currB = headB;
    while(currA!=NULL)
    {
        currA=currA->next;
        lenA++;
    }
    while(currB!=NULL)
    {
        currB=currB->next;
        lenB++;
    }
    currA=headA;
    currB=headB;
    if(lenA>lenB)
    {
        int k = lenA-lenB;
        while(k)
        {
            currA=currA->next;
            k--;
        }
        while(currA!=NULL&&currB!=NULL)
        {
            if((currA)==(currB))
            {
                return currA;
            }
            currA=currA->next;
            currB=currB->next;
        }
        return NULL;
    }
    else
    {
        int k = lenB-lenA;
        while(k)
        {
            currB=currB->next;
            k--;
        }
        while(currA!=NULL&&currB!=NULL)
        {
            if((currA)==(currB))
            {
                return currA;
            }
            currA=currA->next;
            currB=currB->next;
        }
        return NULL;
    }
    
}

方法二、

第一种方法的改善

实现思路

实现思路和第一种方法相似,就是判断时少了一些判断。

时间复杂度和空间复杂度

时间复杂度:O(N)
空间复杂度:O(1)

代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL)
    {
        return NULL;
    }
   
    int lenA = 1;
    int lenB = 1;
    struct ListNode * currA = headA;
    struct ListNode * currB = headB;
    while(currA->next!=NULL)
    {
        currA=currA->next;
        lenA++;
    }
    while(currB->next!=NULL)
    {
        currB=currB->next;
        lenB++;
    }
    if(currA!=currB)
    {
        return NULL;
    }
    struct ListNode * shortList = headA;
    struct ListNode * longList = headB;
    if(lenA>lenB)
    {
        shortList=headB;
        longList=headA;
    }
    int gap = abs(lenA-lenB);
    while(gap--)
    {
        longList=longList->next;
    }
    while(shortList!=longList)
    {
        shortList=shortList->next;
        longList=longList->next;
    }
    return shortList;
}

方法三、

双指针法

实现思路

将两个指针currA和currB指向两个链表的头结点,当currA和currB指向NULL时,就让currA从headB开始重新遍历listB,让currB从headA开始重新遍历listA。当两个指针指向同一个结点时,说明该结点为两个链表的相交结点,当最后两个指针指向的结点都没有相等时,此时两个指针都指向NULL,就说明两个链表没有相交结点,返回NULL。

时间复杂度和空间复杂度

时间复杂度:O(A+B)
空间复杂度:O(1)

代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL)
    {
        return NULL;
    }
   
    struct ListNode * currA = headA;
    struct ListNode * currB = headB;
    while(currA!=currB)  
    //currA和currB将两个表都遍历一遍,此时currA和currB遍历的结点数一样,为A+B的结点数,
    //所以如果A和B有相交结点时,此时currA==currB,会跳出循环,此时currA和currB指向的都是相交的首结点
    //如果遍历到最后还没有跳出循环,则就currA和currB都指向NULL时跳出循环,此时没有相交结点,返回NULL。
    {
        currA = currA==NULL ? headB : currA->next;
        currB = currB==NULL ? headA : currB->next;
    }
    return currA;
}

方法四、

变为环求环的入口点

实现思路

将两个链表的尾结点的next指向一个链表的头结点,此时两个链表变为一个带环的链表,求出带环链表的入环结点就是两个链表的相交结点。此方法调用了求环形链表入环点的方法,但是力扣的习题判定了该方法改变了链表结构,所以测试不会给予通过。
在这里插入图片描述
显示的结果都是对的,但是因为改变了链表结构,所以测试不会通过
在这里插入图片描述

时间复杂度和空间复杂度

代码

 struct ListNode *detectCycle(struct ListNode *head) {
    if(head==NULL||head->next==NULL)
    {
        return NULL;
    }
    struct ListNode * slow = head;
    struct ListNode * fast = head;
    while((fast!=NULL)&&(fast->next!=NULL))
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            struct ListNode * start = head;
            while(start!=slow)
            {
                start=start->next;
                slow=slow->next;
            }
            return slow;
        }
    }
    return NULL;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL)
    {
        return NULL;
    }
    struct ListNode * tail = headB;
    while((tail->next)!=NULL)
    {
        tail=tail->next;
    }
    tail->next = headB;
    return detectCycle(headA);
}

总结

该题的第一个和第二个方法类似,都是先求出两个链表的长度,然后让长的链表先走,然后再让两个链表一起向后走。
第三个方法使用两个指针,这两个指针都将两个链表遍历了一遍,当在相交点时,两个指针遍历的结点数是一样的,所以两个指针相遇的第一个结点就是两个链表的相交点。
第四个方法就是环形链表的方法的逆置,只是提供一个思路,但是实现起来的时间复杂度会比正常方法的时间复杂度大很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值