LeetCode ——160. 相交链表,142. 环形链表 II

简介: ✅<1>主页:C语言的前男友📃<2>知识讲解:LeetCode经典链表笔试题目🔥<3>创作者:C语言的前男友☂️<4>开发环境:Visual Studio 2022🏡<5>系统环境:Windows 10💬<6>前言:今天来讲解几个经典的链表题目,链接已经给出大家可以挑战一下。

160. 相交链表

题目链接:160. 相交链表

题目描述:

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


5dd45a18b78f4207beb216f2e6a21649.png


思路一:

如果两个链表相交,则必有公共结点,我们只需要返回第一个公共结点就可以了,第一个公共结点就是第一个相交结点。怎么找他的第一个公共结点呢?最简单的就是两个循环,去遍历两个链表。用链表B中的结点挨个与链表A的结点比较是否相等。如果存在相等的结点,第一个相等的结点就是两个单链表相交的起始节点,返回任意一个结点。如果没有相交结点,那么两个链表不相交,返回 NULL 。此方法时间复杂度为O(n^2).

代码:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    for(struct ListNode*i=headA;i!=NULL;i=i->next)
    {
        for(struct ListNode*j=headB;j!=NULL;j=j->next)
        {
            if(i==j)
            {
                return i;
            }
        }
    }
    return NULL;
}

思路二:

如果让两个指针能从下面的地方开始走,那么两个指针相遇的时候一定就是两个单链表相交的起始节点。


e6b5d039b4b34bf28d4228d1236c49cf.png


那么问题就是怎么找到这两个位置。其实不难发现只要让 curB 先走,让 curB 之后的链表节点数与 curA 后面的节点数一样。只要让长的链表先走 长链表比短链表多的节点数的 步数,就可以了。

代码:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode*listA=headA;
    struct ListNode*listB=headB;
    int countA=0; //A链表的长度
    int countB=0; //B链表的长度
    //计算B链表的长度
    while(listA) 
    {
        countA++;
        listA=listA->next;
    }
    //计算A链表的长度
    while(listB)
    {
        countB++;
        listB=listB->next;
    }
    //计算长度差
    int n=abs(countA-countB);
    //先假设A为长链表,B为短炼表
    struct ListNode*longlist=headA;
    struct ListNode*shortlist=headB;
    //如果不符合就纠正一下
    if(countB>countA)
    {
        longlist=headB;
        shortlist=headA;
    }
    //让长链表先走
    while(n--)
    {
        longlist=longlist->next;
    }
    //长短链表同时走
    while(longlist&&shortlist)
    {
        //第一次相遇就是相交的第一个结点
        if(longlist==shortlist)
        {
            return longlist;
        }
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
    return NULL;
}


142. 环形链表 II

题目链接:142. 环形链表 II

题目描述:

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。



思路一:

利用带环链表的特点加上严格的逻辑推导:


17d7ea310a224805867ff3cd87eaa614.png


代码:

struct ListNode *detectCycle(struct ListNode *head){
    struct ListNode*frist=head;//快指针
    struct ListNode*slow=head;//慢指针
    //如果遇到结点为空,就说明不是带环结点,直接返回NULL
    while(frist&&frist->next)
    {
        frist=frist->next->next; //快指针一次走两步
        slow=slow->next; //慢指针一次走一步
        if(frist==slow)//在环中相遇
        {
            struct ListNode*meet=frist;//一个从环中走
            struct ListNode*cur=head;//一个从链表头走
            while(meet!=cur)//相遇是循环结束
            {
                meet=meet->next;
                cur=cur->next;
            }
            return meet;//相遇的结点就是环入口点
        }
    }
    return NULL;
}

思路二:

利用快慢指针,让两指针在环中相遇点,将相遇点拆开。相遇点的后一个结点变成新的头节点,相遇点的next指向NULL。这样带环问题就变成了,两个链表相交的问题。


e61e165f1ba04e88a78f9178db343917.png


产生的两条新的链表,head 和 phead  ,两条链表相交的第一个的以公共结点就是,以前带环链表的环入口处。


代码:

//找到链表相交的第一个结点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode*listA=headA;
    struct ListNode*listB=headB;
    int countA=0;
    int countB=0;
    while(listA)
    {
        countA++;
        listA=listA->next;
    }
    while(listB)
    {
        countB++;
        listB=listB->next;
    }
    int n=abs(countA-countB);
    struct ListNode*longlist=headA;
    struct ListNode*shortlist=headB;
    if(countB>countA)
    {
        longlist=headB;
        shortlist=headA;
    }
    while(n--)
    {
        longlist=longlist->next;
    }
    while(longlist&&shortlist)
    {
        if(longlist==shortlist)
        {
            return longlist;
        }
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
    return NULL;
}
struct ListNode *detectCycle(struct ListNode *head)
{
    struct ListNode*frist=head;
    struct ListNode*slow=head;
    while(frist&&frist->next)
    {
        frist=frist->next->next;
        slow=slow->next;
        //快慢指针在环中相遇
        if(frist==slow)
        {
            //拆分环行链表段
            struct ListNode*phead=frist->next;
            slow->next=NULL;
            //返回相交结点
            return getIntersectionNode(phead,head);
        }
    }
    return NULL;
}


最后:成为自己想成为的样子,才能得到自己想得到的东西。


 

相关文章
|
20天前
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
31 1
|
27天前
Leetcode第21题(合并两个有序链表)
这篇文章介绍了如何使用非递归和递归方法解决LeetCode第21题,即合并两个有序链表的问题。
44 0
Leetcode第21题(合并两个有序链表)
|
24天前
|
算法
❤️算法笔记❤️-(每日一刷-160、相交链表)
❤️算法笔记❤️-(每日一刷-160、相交链表)
16 1
|
27天前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
14 0
LeetCode第二十四题(两两交换链表中的节点)
|
27天前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
37 0
Leetcode第十九题(删除链表的倒数第N个节点)
|
27天前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
71 0
|
27天前
【LeetCode 10】142. 环形链表 II
【LeetCode 10】142. 环形链表 II
18 0
|
5月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
5月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
5月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
48 2