环形链表OJ题解析

环形链表类型的题目比普通的单向链表复杂,往往需要涉及到一些数学

首先请出今天的主角:142. 环形链表 II - 力扣(LeetCode)

环形链表OJ题解析_第1张图片

首先通读一下题目,它让我们返回链表入环的第一个节点,如果无环,则返回NULL。那么第一个问题就是怎么判断这个链表有没有环,这其实也是一道OJ题:141. 环形链表 - 力扣(LeetCode)

这里就要用到我们的快慢指针了,先简单画个图

定义两个指针,fast每次走两步,slow走一步

环形链表OJ题解析_第2张图片

假设有环,那么最终两个指针都会进到环里,那我们就想是不是当两个指针相遇时,就能说明链表有环了呢,但是问题又来了,一定会相遇吗,来简单证明一下

假设slow入环后,fast和slow的距离为N,因为前面假设了fast走两步,slow走一步,因此fast离slow的距离每次减一,最终N一定会减到0,这就证明了让fast走两步,slow走一步的情况下,如果链表有环,两个指针是一定可以相遇的,那么判断链表有没有环就很简单了,代码端上来

struct ListNode* fast = head,*slow = head;

while (fast && fast->next) // 为空的话肯定不是环了
{
    fast = fast->next->next;
    slow = slow->next;
    if (fast == slow)
        return true; // 这里只是举个例子,假设有环返回true,本题并不需要
}
    
return false;

有些小伙伴们可能会想,那fast每次走三步,slow每次走一步行不行呢,能不能相遇呢,我们也来证明一下。

这时候fast和slow的距离每次就减2,如果N是偶数的话,依然可以减到零,也就是相遇。而当N是奇数的时候,fast在快要追上slow,也就是距离为1时,下一次再走就超过了,这时候距离变成了C-1(这里假设这个圆环的周长为C),再来分类讨论,如果C是奇数,那么C-1就是偶数,显然二者可以再次相遇,那如果C是偶数呢,是不是这种情况两者一定无法相遇呢,非也。

环形链表OJ题解析_第3张图片

 

假设从头节点到入环的长度为L,由于slow走1步fast能走3步,所以slow走的距离(L)乘三倍就是fast走的距离,就得到第一条公式:3L = nC - N + L,这里n是fast在环里转的圈数,因为环有多大,入环前有多长都是未知的,所以n也是未知的,化简后得到上面第二条公式,这时候心里就有底了。2L是偶数,我们讨论的这种情况C是偶数,那么无论n是奇数还是偶数,nC都是偶数,这时候N没得选了,只能是偶数,所以我们上面的假设从一开始就错了,在C是偶数的情况下,N不可能是奇数,因此fast一定可以追上slow。

言归正传,判断出链表带环之后,怎么找到入环的第一个节点呢,还是画图

环形链表OJ题解析_第4张图片

这里我们是以fast走两步,slow走一步来做的。假设两个指针相遇时距离入环点距离为X,链表头节点到入环点长度依旧为L,易得:2(L+X) = nC + X + L  , 化简后:L = nC - X 。这个公式看起来全是未知数,但其实已经得到我们想要的信息了。假设一个指针从头节点开始走到入环点,此时长度为L,另一个指针从相遇点开始走,它走了nC - X ,这时候这个指针刚好也在入环点(可理解为在相遇点走了n圈后又少走了X),这就说明我们让一个指针从头节点开始走,另一个指针从相遇点开始走,每次走一步,当它们相遇时的那个节点就是入环点!最后代码收尾

struct ListNode* detectCycle(struct ListNode* head) 
{
    struct ListNode* slow = head,*fast = head;

    while (fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;

        if (fast == slow)
        {
            struct ListNode* meet = fast; // 记录下相遇点

            while (head != meet)
            {
                head = head->next;
                meet = meet->next;           
            }
            return meet;
        }
    }
    return NULL;
}

你可能感兴趣的:(链表,数据结构)