力扣142. 环形链表 II

题目

给定一个链表的头节点head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。

链接:142. 环形链表 II - 力扣(LeetCode)

题解

方法一:设置两个指针,一个指针指向链表头结点,一个指针指向判环时快慢指针相遇的位置,然后两个指针同时走,它们会在环的第一个结点处相遇。

判断链表是否有环:力扣141. 环形链表_啊哈leelee~的博客-CSDN博客

证明如下。

假设链表起始结点head到环起始结点head'的距离为L,环起始结点head'到快慢指针相遇结点meet的距离为X,环的长度为C,则meet到head'的距离为C-X。

在判环时,慢指针slow走的路径长度为L+X,快指针fast走的路径长度为L+nC+X(n>=1)。而fast所走路径长度是slow所走路径长度的2倍,即L+nC+X=2*(L+X) ,展开得L= nC-X,也就是L=(n-1)C+C-X。即一个指针从head开始走,一个指针从meet开始走,这两个指针一定会在环起始结点相遇。

注意,在slow进环之前,fast可能已经在环里走了n圈了;slow进环之后,fast一定会在一圈之内追上slow,因为slow和fast之间的距离最大是C,而slow和fast每移动一次,它们俩之间的距离就会减1,所以在slow移动一圈之前fast一定会追上。

代码如下:

struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //寻找快慢指针相遇结点
        if (slow == fast)
        {
            //寻找环起始结点
            struct ListNode* meet = slow;
            while (head != meet)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

方法二:设置一个指针meet指向快慢指针相遇的位置,设置一个指针meetNext指向meet的next,然后把meet的next置空,把问题转化为求解两个链表相交结点。如下图所示,问题转化为求解以head为头结点的链表以meetNext为头结点的链表相交结点

求解链表相交结点:力扣160. 相交链表_啊哈leelee~的博客-CSDN博客

代码如下:

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
    struct ListNode* tailA = headA;
    struct ListNode* tailB = headB;
    int lenA = 1;
    int lenB = 1;
    while (tailA->next)
    {
        tailA = tailA->next;
        lenA++;
    }
    while (tailB->next)
    {
        tailB = tailB->next;
        lenB++;
    }
    if (tailA != tailB)
        return NULL;

    struct ListNode* longList = headA;
    struct ListNode* shortList = headB;
    if (lenA < lenB)
    {
        longList = headB;
        shortList = headA;
    }
    int gap = abs(lenA - lenB);
    while (gap--)
    {
        longList = longList->next;
    }
    while (longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;
    }
    return longList;
}

struct ListNode* detectCycle(struct ListNode* head)
{
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //找到相遇结点
        if (slow == fast)
        {
            struct ListNode* meet = slow;
            struct ListNode* meetNext = meet->next;
            meet->next = NULL;
            head = getIntersectionNode(head, meetNext);
            return head;
        }
    }
    return NULL;
}
相关推荐
辞半夏丶北笙1 分钟前
最近最少使用算法(LRU最近最少使用)缓存替换算法
java·算法·缓存
BingLin-Liu2 分钟前
蓝桥杯备考:六大排序算法
算法·排序算法
南玖yy10 分钟前
C语言:数组的介绍与使用
c语言·开发语言·算法
小菜鸟博士13 分钟前
手撕Vision Transformer -- Day1 -- 基础原理
人工智能·深度学习·学习·算法·面试
wclass-zhengge18 分钟前
04树 + 堆 + 优先队列 + 图(D1_树(D6_B树(B)))
数据结构·b树
灰灰老师1 小时前
数据分析系列--[11] RapidMiner,K-Means聚类分析(含数据集)
人工智能·算法·机器学习·数据挖掘·数据分析·kmeans·rapidminer
追求源于热爱!2 小时前
记4(可训练对象+自动求导机制+波士顿房价回归预测
图像处理·人工智能·算法·机器学习·回归
qq_433618442 小时前
哈夫曼树
数据结构·算法
Icomi_3 小时前
【PyTorch】7.自动微分模块:开启神经网络 “进化之门” 的魔法钥匙
c语言·c++·人工智能·pytorch·python·机器学习·计算机视觉
余辉zmh3 小时前
【贪心算法篇】:“贪心”之旅--算法练习题中的智慧与策略(二)
c++·算法·leetcode·贪心算法